@sveltia/ui 0.63.1 → 0.65.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 (48) hide show
  1. package/dist/components/drawer/drawer.svelte.d.ts +2 -2
  2. package/dist/components/emoji/cache.d.ts +3 -0
  3. package/dist/components/emoji/cache.js +96 -0
  4. package/dist/components/emoji/caret.d.ts +2 -0
  5. package/dist/components/emoji/caret.js +106 -0
  6. package/dist/components/emoji/emoji-suggestions.svelte +424 -0
  7. package/dist/components/emoji/emoji-suggestions.svelte.d.ts +66 -0
  8. package/dist/components/emoji/emoji.d.ts +31 -0
  9. package/dist/components/emoji/emoji.js +208 -0
  10. package/dist/components/emoji/loader.d.ts +6 -0
  11. package/dist/components/emoji/loader.js +74 -0
  12. package/dist/components/text-editor/emoji-autocomplete.svelte +225 -0
  13. package/dist/components/text-editor/emoji-autocomplete.svelte.d.ts +12 -0
  14. package/dist/components/text-editor/shiki/generated.d.ts +1 -1
  15. package/dist/components/text-editor/shiki/generated.js +1 -1
  16. package/dist/components/text-editor/store.svelte.js +1 -0
  17. package/dist/components/text-editor/text-editor.svelte +9 -0
  18. package/dist/components/text-editor/text-editor.svelte.d.ts +10 -0
  19. package/dist/components/text-field/emoji-autocomplete.svelte +165 -0
  20. package/dist/components/text-field/emoji-autocomplete.svelte.d.ts +25 -0
  21. package/dist/components/text-field/text-area.svelte +11 -0
  22. package/dist/components/text-field/text-area.svelte.d.ts +19 -1
  23. package/dist/components/text-field/text-input.svelte +7 -0
  24. package/dist/components/text-field/text-input.svelte.d.ts +10 -0
  25. package/dist/locales/ar.yaml +3 -0
  26. package/dist/locales/bg.yaml +3 -0
  27. package/dist/locales/ca.yaml +3 -0
  28. package/dist/locales/cs.yaml +3 -0
  29. package/dist/locales/el.yaml +3 -0
  30. package/dist/locales/en-CA.yaml +3 -0
  31. package/dist/locales/en-GB.yaml +3 -0
  32. package/dist/locales/en-US.yaml +3 -0
  33. package/dist/locales/es-CO.yaml +116 -0
  34. package/dist/locales/fi.yaml +3 -0
  35. package/dist/locales/fr.yaml +3 -0
  36. package/dist/locales/ja.yaml +3 -0
  37. package/dist/locales/ko.yaml +3 -0
  38. package/dist/locales/nl.yaml +3 -0
  39. package/dist/locales/pl.yaml +3 -0
  40. package/dist/locales/pt-BR.yaml +3 -0
  41. package/dist/locales/pt-PT.yaml +3 -0
  42. package/dist/locales/ru.yaml +3 -0
  43. package/dist/locales/tr.yaml +3 -0
  44. package/dist/locales/uk.yaml +3 -0
  45. package/dist/locales/zh-CN.yaml +3 -0
  46. package/dist/typedefs.d.ts +61 -0
  47. package/dist/typedefs.js +34 -0
  48. package/package.json +5 -4
@@ -9,6 +9,7 @@
9
9
  import TextArea from '../text-field/text-area.svelte';
10
10
  import Toast from '../toast/toast.svelte';
11
11
  import { BLOCK_BUTTON_TYPES, INLINE_BUTTON_TYPES } from './constants.js';
12
+ import EmojiAutocomplete from './emoji-autocomplete.svelte';
12
13
  import LexicalRoot from './lexical-root.svelte';
13
14
  import { createEditorStore } from './store.svelte.js';
14
15
  import TextEditorToolbar from './toolbar/text-editor-toolbar.svelte';
@@ -28,6 +29,8 @@
28
29
  * @property {TextEditorComponent[]} [components] Editor components.
29
30
  * @property {boolean} [useMarkdownShortcuts] Whether to enable Markdown keyboard shortcuts in the
30
31
  * rich text editor.
32
+ * @property {boolean} [useEmojiAutocomplete] Whether to autocomplete emojis when the user
33
+ * types a shortcode, like `:smi`.
31
34
  * @property {string} [class] The `class` attribute on the wrapper element.
32
35
  * @property {boolean} [hidden] Whether to hide the widget.
33
36
  * @property {boolean} [disabled] Whether to disable the widget. An alias of the `aria-disabled`
@@ -53,6 +56,7 @@
53
56
  buttons = [...INLINE_BUTTON_TYPES, ...BLOCK_BUTTON_TYPES],
54
57
  components = [],
55
58
  useMarkdownShortcuts = true,
59
+ useEmojiAutocomplete = true,
56
60
  hidden = false,
57
61
  disabled = false,
58
62
  readonly = false,
@@ -72,6 +76,7 @@
72
76
  enabledButtons: buttons,
73
77
  components,
74
78
  useMarkdownShortcuts,
79
+ useEmojiAutocomplete,
75
80
  };
76
81
 
77
82
  setContext('editorStore', editorStore);
@@ -115,6 +120,7 @@
115
120
  <TextArea
116
121
  autoResize={true}
117
122
  bind:value={editorStore.inputValue}
123
+ {useEmojiAutocomplete}
118
124
  {flex}
119
125
  {dir}
120
126
  hidden={editorStore.useRichText || hidden}
@@ -123,6 +129,9 @@
123
129
  {required}
124
130
  {invalid}
125
131
  />
132
+ {#if editorStore.config.useEmojiAutocomplete && !disabled && !readonly}
133
+ <EmojiAutocomplete />
134
+ {/if}
126
135
  </div>
127
136
 
128
137
  {#if editorStore.showConverterError}
@@ -34,6 +34,11 @@ declare const TextEditor: import("svelte").Component<{
34
34
  * rich text editor.
35
35
  */
36
36
  useMarkdownShortcuts?: boolean | undefined;
37
+ /**
38
+ * Whether to autocomplete emojis when the user
39
+ * types a shortcode, like `:smi`.
40
+ */
41
+ useEmojiAutocomplete?: boolean | undefined;
37
42
  /**
38
43
  * The `class` attribute on the wrapper element.
39
44
  */
@@ -97,6 +102,11 @@ type Props = {
97
102
  * rich text editor.
98
103
  */
99
104
  useMarkdownShortcuts?: boolean | undefined;
105
+ /**
106
+ * Whether to autocomplete emojis when the user
107
+ * types a shortcode, like `:smi`.
108
+ */
109
+ useEmojiAutocomplete?: boolean | undefined;
100
110
  /**
101
111
  * The `class` attribute on the wrapper element.
102
112
  */
@@ -0,0 +1,165 @@
1
+ <!--
2
+ @component
3
+ Emoji autocomplete for a plain `<input>` or `<textarea>`. Typing a colon followed by one or more
4
+ characters, like `:smi`, brings up a list of matching emojis that can be inserted with a click or
5
+ the Enter key, the same way it works on GitHub, Slack and other apps. This wires the field up to
6
+ `<EmojiSuggestions>`, which owns the dropdown itself.
7
+ -->
8
+ <script>
9
+ import { getFieldCaretRect } from '../emoji/caret.js';
10
+ import { detectEmojiTrigger, getEmojiInsertText } from '../emoji/emoji.js';
11
+ import EmojiSuggestions from '../emoji/emoji-suggestions.svelte';
12
+
13
+ /**
14
+ * @import { EmojiEntry, EmojiTrigger } from '../../typedefs';
15
+ */
16
+
17
+ /**
18
+ * @typedef {object} Props
19
+ * @property {HTMLInputElement | HTMLTextAreaElement} [element] The field to attach the
20
+ * suggestions to.
21
+ */
22
+
23
+ /**
24
+ * A shortcode within a text field, identified by where its colon is, which doesn’t change as the
25
+ * query grows.
26
+ * @typedef {EmojiTrigger & { start: number, end: number }} FieldEmojiTrigger
27
+ */
28
+
29
+ /**
30
+ * @type {Props}
31
+ */
32
+ let {
33
+ /* eslint-disable prefer-const */
34
+ element = undefined,
35
+ /* eslint-enable prefer-const */
36
+ } = $props();
37
+
38
+ /**
39
+ * A reference to the dropdown.
40
+ * @type {ReturnType<typeof EmojiSuggestions> | undefined}
41
+ */
42
+ let list = $state();
43
+
44
+ /**
45
+ * Look for a shortcode being typed right before the caret.
46
+ * @returns {FieldEmojiTrigger | undefined} Shortcode state, if any.
47
+ */
48
+ const findTrigger = () => {
49
+ if (!element || element.disabled || element.readOnly) {
50
+ return undefined;
51
+ }
52
+
53
+ const { value, selectionStart, selectionEnd } = element;
54
+
55
+ // Only suggest at a plain caret, not while a range is selected
56
+ if (selectionStart === null || selectionStart !== selectionEnd) {
57
+ return undefined;
58
+ }
59
+
60
+ const query = detectEmojiTrigger(value.slice(0, selectionStart));
61
+
62
+ if (query === undefined) {
63
+ return undefined;
64
+ }
65
+
66
+ const start = selectionStart - query.length - 1;
67
+
68
+ return { id: String(start), query, start, end: selectionStart };
69
+ };
70
+
71
+ /**
72
+ * Get the viewport-relative bounds of the shortcode being typed.
73
+ * @param {EmojiTrigger} trigger Shortcode state.
74
+ * @returns {ReturnType<typeof getFieldCaretRect>} Bounds, or `undefined` if they can’t be
75
+ * determined.
76
+ */
77
+ const getAnchorRect = (trigger) => {
78
+ const { start, end } = /** @type {FieldEmojiTrigger} */ (trigger);
79
+
80
+ return element ? getFieldCaretRect(element, start, end) : undefined;
81
+ };
82
+
83
+ /**
84
+ * Replace the shortcode being typed with the given emoji.
85
+ * @param {EmojiEntry} entry Emoji to insert.
86
+ * @param {EmojiTrigger} trigger Shortcode to replace.
87
+ */
88
+ const insertEmoji = (entry, trigger) => {
89
+ const { query, start, end } = /** @type {FieldEmojiTrigger} */ (trigger);
90
+
91
+ // Make sure the shortcode is still where it was when the suggestions appeared
92
+ if (!element || element.value.slice(start, end) !== `:${query}`) {
93
+ return;
94
+ }
95
+
96
+ const text = getEmojiInsertText(entry.emoji, element.value.slice(end));
97
+
98
+ element.focus();
99
+ element.setSelectionRange(start, end);
100
+
101
+ // `execCommand()` is deprecated but remains the only way to edit a field without wiping its
102
+ // native undo history, so it’s tried first and `setRangeText()` covers the fallback
103
+ let inserted = false;
104
+
105
+ try {
106
+ inserted = document.execCommand('insertText', false, text);
107
+ } catch {
108
+ inserted = false;
109
+ }
110
+
111
+ if (!inserted) {
112
+ element.setRangeText(text, start, end, 'end');
113
+ // Let Svelte bindings and consumer handlers know the value changed
114
+ element.dispatchEvent(new Event('input', { bubbles: true }));
115
+ }
116
+ };
117
+
118
+ $effect(() => {
119
+ if (!element || !list) {
120
+ return undefined;
121
+ }
122
+
123
+ const field = element;
124
+
125
+ /**
126
+ * Re-examine the text around the caret.
127
+ */
128
+ const refresh = () => {
129
+ list?.update(findTrigger());
130
+ };
131
+
132
+ /**
133
+ * Give the list first refusal on the keys it drives. Anything it doesn’t take is left to the
134
+ * field, and the `keyup` listener below picks up wherever the caret ends up.
135
+ * @param {Event} event `keydown` event.
136
+ */
137
+ const onKeyDown = (event) => {
138
+ list?.handleKeyDown(/** @type {KeyboardEvent} */ (event));
139
+ };
140
+
141
+ /**
142
+ * Close the list when the field loses the focus.
143
+ */
144
+ const onBlur = () => {
145
+ list?.close();
146
+ };
147
+
148
+ field.addEventListener('keydown', onKeyDown);
149
+ field.addEventListener('keyup', refresh);
150
+ field.addEventListener('input', refresh);
151
+ field.addEventListener('mouseup', refresh);
152
+ field.addEventListener('blur', onBlur);
153
+
154
+ return () => {
155
+ field.removeEventListener('keydown', onKeyDown);
156
+ field.removeEventListener('keyup', refresh);
157
+ field.removeEventListener('input', refresh);
158
+ field.removeEventListener('mouseup', refresh);
159
+ field.removeEventListener('blur', onBlur);
160
+ list?.close();
161
+ };
162
+ });
163
+ </script>
164
+
165
+ <EmojiSuggestions bind:this={list} {getAnchorRect} onSelect={insertEmoji} ariaOwner={element} />
@@ -0,0 +1,25 @@
1
+ export default EmojiAutocomplete;
2
+ type EmojiAutocomplete = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<Props>): void;
5
+ };
6
+ /**
7
+ * Emoji autocomplete for a plain `<input>` or `<textarea>`. Typing a colon followed by one or more
8
+ * characters, like `:smi`, brings up a list of matching emojis that can be inserted with a click or
9
+ * the Enter key, the same way it works on GitHub, Slack and other apps. This wires the field up to
10
+ * `<EmojiSuggestions>`, which owns the dropdown itself.
11
+ */
12
+ declare const EmojiAutocomplete: import("svelte").Component<{
13
+ /**
14
+ * The field to attach the
15
+ * suggestions to.
16
+ */
17
+ element?: HTMLInputElement | HTMLTextAreaElement | undefined;
18
+ }, {}, "">;
19
+ type Props = {
20
+ /**
21
+ * The field to attach the
22
+ * suggestions to.
23
+ */
24
+ element?: HTMLInputElement | HTMLTextAreaElement | undefined;
25
+ };
@@ -6,6 +6,8 @@
6
6
  @see https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/
7
7
  -->
8
8
  <script>
9
+ import EmojiAutocomplete from './emoji-autocomplete.svelte';
10
+
9
11
  /**
10
12
  * @import { Snippet } from 'svelte';
11
13
  * @import { CommonEventHandlers, InputEventHandlers } from '../../typedefs';
@@ -14,11 +16,14 @@
14
16
  /**
15
17
  * @typedef {object} Props
16
18
  * @property {string} [value] Input value.
19
+ * @property {HTMLTextAreaElement} [element] A reference to the `<textarea>` element.
17
20
  * @property {boolean} [flex] Make the text input container flexible.
18
21
  * @property {'ltr' | 'rtl' | 'auto'} [dir] The `dir` attribute on the `<textarea>` element.
19
22
  * @property {string} [name] The `name` attribute on the `<textarea>` element.
20
23
  * @property {boolean} [autoResize] Whether to automatically resize the `<textarea>` based on the
21
24
  * content.
25
+ * @property {boolean} [useEmojiAutocomplete] Whether to autocomplete emojis when the user
26
+ * types a shortcode, like `:smi`.
22
27
  * @property {string} [class] The `class` attribute on the wrapper element.
23
28
  * @property {boolean} [hidden] Whether to hide the widget.
24
29
  * @property {boolean} [disabled] Whether to disable the widget. An alias of the `aria-disabled`
@@ -38,10 +43,12 @@
38
43
  let {
39
44
  /* eslint-disable prefer-const */
40
45
  value = $bindable(''),
46
+ element = $bindable(),
41
47
  flex = false,
42
48
  dir = undefined,
43
49
  name = undefined,
44
50
  autoResize = false,
51
+ useEmojiAutocomplete = false,
45
52
  class: className,
46
53
  hidden = false,
47
54
  disabled = false,
@@ -63,6 +70,7 @@
63
70
  {hidden}
64
71
  >
65
72
  <textarea
73
+ bind:this={element}
66
74
  {...restProps}
67
75
  {dir}
68
76
  {name}
@@ -78,6 +86,9 @@
78
86
  {#if autoResize}
79
87
  <div class="clone" aria-hidden="true" {dir}>{value}</div>
80
88
  {/if}
89
+ {#if useEmojiAutocomplete && !disabled && !readonly}
90
+ <EmojiAutocomplete {element} />
91
+ {/if}
81
92
  </div>
82
93
 
83
94
  <style>.text-area {
@@ -14,6 +14,10 @@ declare const TextArea: import("svelte").Component<import("../../typedefs").Keyb
14
14
  * Input value.
15
15
  */
16
16
  value?: string | undefined;
17
+ /**
18
+ * A reference to the `<textarea>` element.
19
+ */
20
+ element?: HTMLTextAreaElement | undefined;
17
21
  /**
18
22
  * Make the text input container flexible.
19
23
  */
@@ -31,6 +35,11 @@ declare const TextArea: import("svelte").Component<import("../../typedefs").Keyb
31
35
  * content.
32
36
  */
33
37
  autoResize?: boolean | undefined;
38
+ /**
39
+ * Whether to autocomplete emojis when the user
40
+ * types a shortcode, like `:smi`.
41
+ */
42
+ useEmojiAutocomplete?: boolean | undefined;
34
43
  /**
35
44
  * The `class` attribute on the wrapper element.
36
45
  */
@@ -63,12 +72,16 @@ declare const TextArea: import("svelte").Component<import("../../typedefs").Keyb
63
72
  * Primary slot content.
64
73
  */
65
74
  children?: Snippet<[]> | undefined;
66
- } & Record<string, any>, {}, "value">;
75
+ } & Record<string, any>, {}, "value" | "element">;
67
76
  type Props = {
68
77
  /**
69
78
  * Input value.
70
79
  */
71
80
  value?: string | undefined;
81
+ /**
82
+ * A reference to the `<textarea>` element.
83
+ */
84
+ element?: HTMLTextAreaElement | undefined;
72
85
  /**
73
86
  * Make the text input container flexible.
74
87
  */
@@ -86,6 +99,11 @@ type Props = {
86
99
  * content.
87
100
  */
88
101
  autoResize?: boolean | undefined;
102
+ /**
103
+ * Whether to autocomplete emojis when the user
104
+ * types a shortcode, like `:smi`.
105
+ */
106
+ useEmojiAutocomplete?: boolean | undefined;
89
107
  /**
90
108
  * The `class` attribute on the wrapper element.
91
109
  */
@@ -7,6 +7,7 @@
7
7
  <script>
8
8
  import { activateKeyShortcuts } from '@sveltia/utils/events';
9
9
  import TruncatedText from '../typography/truncated-text.svelte';
10
+ import EmojiAutocomplete from './emoji-autocomplete.svelte';
10
11
 
11
12
  /**
12
13
  * @import { CommonEventHandlers, InputEventHandlers, TextInputProps } from '../../typedefs';
@@ -15,6 +16,8 @@
15
16
  /**
16
17
  * @typedef {object} Props
17
18
  * @property {string} [value] Input value.
19
+ * @property {boolean} [useEmojiAutocomplete] Whether to autocomplete emojis when the user
20
+ * types a shortcode, like `:smi`.
18
21
  */
19
22
 
20
23
  /**
@@ -33,6 +36,7 @@
33
36
  flex = false,
34
37
  monospace = false,
35
38
  debounce = false,
39
+ useEmojiAutocomplete = false,
36
40
  class: className,
37
41
  hidden = false,
38
42
  disabled = false,
@@ -118,6 +122,9 @@
118
122
  oninputcapture={handleInput}
119
123
  {@attach activateKeyShortcuts(keyShortcuts)}
120
124
  />
125
+ {#if useEmojiAutocomplete && !disabled && !readonly}
126
+ <EmojiAutocomplete {element} />
127
+ {/if}
121
128
  {#if ariaLabel && showInlineLabel}
122
129
  <span id="{id}-label" class="label" class:hidden={!!value} aria-hidden="true">
123
130
  <TruncatedText>
@@ -13,12 +13,22 @@ declare const TextInput: import("svelte").Component<TextInputProps & import("../
13
13
  * Input value.
14
14
  */
15
15
  value?: string | undefined;
16
+ /**
17
+ * Whether to autocomplete emojis when the user
18
+ * types a shortcode, like `:smi`.
19
+ */
20
+ useEmojiAutocomplete?: boolean | undefined;
16
21
  } & Record<string, any>, {}, "value" | "element">;
17
22
  type Props = {
18
23
  /**
19
24
  * Input value.
20
25
  */
21
26
  value?: string | undefined;
27
+ /**
28
+ * Whether to autocomplete emojis when the user
29
+ * types a shortcode, like `:smi`.
30
+ */
31
+ useEmojiAutocomplete?: boolean | undefined;
22
32
  };
23
33
  import type { TextInputProps } from '../../typedefs';
24
34
  import type { InputEventHandlers } from '../../typedefs';
@@ -18,6 +18,9 @@ expand: توسيع
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: تجاهل
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: اقتراحات الرموز التعبيرية
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Разгъни
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Отхвърли
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Предложения за емоджи
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Desplega
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Descarta
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Suggeriments d’emoji
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Rozbalit
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Zavřít
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Návrhy emodži
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Ανάπτυξη
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Παράβλεψη
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Προτάσεις emoji
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Expand
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Dismiss
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Emoji Suggestions
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Expand
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Dismiss
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Emoji Suggestions
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Expand
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Dismiss
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Emoji Suggestions
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -0,0 +1,116 @@
1
+ # Dialog action button labels
2
+ ok: OK
3
+ cancel: Cancelar
4
+ close: Cerrar
5
+
6
+ # Button to clear content, e.g. search input or calendar date
7
+ clear: Limpiar
8
+
9
+ # Text editor dialog buttons for link/image insertion
10
+ insert: Insertar
11
+ update: Actualizar
12
+ remove: Quitar
13
+
14
+ # Combobox dropdown toggle button aria-labels
15
+ collapse: Contraer
16
+ expand: Expandir
17
+
18
+ # Infobar/toast dismiss button label
19
+ dismiss: Descartar
20
+
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Sugerencias de emojis
23
+
24
+ # Calendar component
25
+ calendar:
26
+ # View switcher group aria-labels and navigation button aria-labels
27
+ year: Año
28
+ previous_decade: Década anterior
29
+ next_decade: Década siguiente
30
+ month: Mes
31
+ previous_month: Mes anterior
32
+ next_month: Mes siguiente
33
+ # “Today” button label in footer
34
+ today: Hoy
35
+
36
+ # Split button component
37
+ split_button:
38
+ # Wrapper aria-label, e.g. “Save Options” when primary button is “Save”
39
+ x_options: 'Opciones de {$name}'
40
+ # Dropdown toggle aria-label
41
+ more_options: Más opciones
42
+
43
+ # Combobox component
44
+ combobox:
45
+ # Placeholder when no option is selected
46
+ select_an_option: Selecciona una opción…
47
+ # Filter input aria-label
48
+ filter_options: Filtrar opciones
49
+ # Empty state message when filter has no matches
50
+ no_matching_options: No se encontraron opciones coincidentes
51
+
52
+ # Number input component
53
+ number_input:
54
+ # Spin button aria-labels for incrementing/decrementing the number value
55
+ increase: Aumentar
56
+ decrease: Disminuir
57
+
58
+ # Password input component
59
+ password_input:
60
+ # Visibility toggle button aria-labels
61
+ show_password: Mostrar la contraseña
62
+ hide_password: Ocultar la contraseña
63
+
64
+ # Secret input component (API keys, tokens, etc.)
65
+ secret_input:
66
+ # Visibility toggle button aria-labels
67
+ show_secret: Mostrar el secreto
68
+ hide_secret: Ocultar el secreto
69
+
70
+ # Select tags component (multi-select)
71
+ select_tags:
72
+ # Listbox aria-label
73
+ selected_options: Opciones seleccionadas
74
+ # Remove button aria-label, e.g. “Remove Option 1”
75
+ remove_x: 'Quitar {$name}'
76
+
77
+ # Text editor component
78
+ text_editor:
79
+ # Toolbar aria-labels
80
+ text_editor: Editor de texto
81
+ code_editor: Editor de código
82
+ # Block style menu button and menu aria-labels
83
+ text_style_options: Opciones de estilo de texto
84
+ show_text_style_options: Mostrar las opciones de estilo de texto
85
+ # Block style menu items
86
+ paragraph: Párrafo
87
+ heading_1: Encabezado 1
88
+ heading_2: Encabezado 2
89
+ heading_3: Encabezado 3
90
+ heading_4: Encabezado 4
91
+ heading_5: Encabezado 5
92
+ heading_6: Encabezado 6
93
+ bulleted_list: Lista con viñetas
94
+ numbered_list: Lista numerada
95
+ blockquote: Cita
96
+ code_block: Bloque de código
97
+ # Inline style button aria-labels
98
+ bold: Negrita
99
+ italic: Cursiva
100
+ strikethrough: Tachado
101
+ code: Código
102
+ link: Enlace
103
+ # Link dialog title
104
+ insert_link: Insertar enlace
105
+ update_link: Actualizar enlace
106
+ # Link dialog input field labels
107
+ text: Texto
108
+ url: URL
109
+ # Markdown mode toggle button aria-label
110
+ edit_in_markdown: Editar en Markdown
111
+ # Error message when rich text conversion fails
112
+ converter_error: No se pudo activar el modo de texto enriquecido. Usa el editor de texto sin formato en su lugar.
113
+ # Language selector aria-label
114
+ language: Idioma
115
+ # Plain text mode option in language selector
116
+ plain_text: Texto sin formato
@@ -18,6 +18,9 @@ expand: Näytä
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Hylkää
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Emoji-ehdotukset
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: Développer
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Ignorer
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: Suggestions d’émojis
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: 広げる
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 閉じる
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: 絵文字の候補
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels
@@ -18,6 +18,9 @@ expand: 펼치기
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 닫기
20
20
 
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: 이모지 제안
23
+
21
24
  # Calendar component
22
25
  calendar:
23
26
  # View switcher group aria-labels and navigation button aria-labels