@devicai/ui 0.57.0 → 0.58.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 (171) hide show
  1. package/README.md +162 -0
  2. package/dist/cjs/api/types.js.map +1 -1
  3. package/dist/cjs/components/AICommandBar/AICommandBar.js +10 -7
  4. package/dist/cjs/components/AICommandBar/AICommandBar.js.map +1 -1
  5. package/dist/cjs/components/AICommandBar/useAICommandBar.js +7 -5
  6. package/dist/cjs/components/AICommandBar/useAICommandBar.js.map +1 -1
  7. package/dist/cjs/components/AIElementWrapper/AIElementWrapper.js +17 -14
  8. package/dist/cjs/components/AIElementWrapper/AIElementWrapper.js.map +1 -1
  9. package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js +7 -5
  10. package/dist/cjs/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
  11. package/dist/cjs/components/AIGenerationButton/AIGenerationButton.js +11 -6
  12. package/dist/cjs/components/AIGenerationButton/AIGenerationButton.js.map +1 -1
  13. package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js +6 -4
  14. package/dist/cjs/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
  15. package/dist/cjs/components/ChatDrawer/ChatDrawer.js +26 -12
  16. package/dist/cjs/components/ChatDrawer/ChatDrawer.js.map +1 -1
  17. package/dist/cjs/components/ChatDrawer/ChatInput.js +21 -15
  18. package/dist/cjs/components/ChatDrawer/ChatInput.js.map +1 -1
  19. package/dist/cjs/components/ChatDrawer/ChatMessages.js +54 -13
  20. package/dist/cjs/components/ChatDrawer/ChatMessages.js.map +1 -1
  21. package/dist/cjs/components/ChatDrawer/CompactionWidget.js +13 -4
  22. package/dist/cjs/components/ChatDrawer/CompactionWidget.js.map +1 -1
  23. package/dist/cjs/components/ChatDrawer/ConversationSelector.js +6 -4
  24. package/dist/cjs/components/ChatDrawer/ConversationSelector.js.map +1 -1
  25. package/dist/cjs/components/ChatDrawer/GuardrailNotice.js +40 -0
  26. package/dist/cjs/components/ChatDrawer/GuardrailNotice.js.map +1 -0
  27. package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js +3 -1
  28. package/dist/cjs/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
  29. package/dist/cjs/components/ChatDrawer/LimitBanner.js +19 -9
  30. package/dist/cjs/components/ChatDrawer/LimitBanner.js.map +1 -1
  31. package/dist/cjs/components/ChatDrawer/QueueNotice.js +19 -7
  32. package/dist/cjs/components/ChatDrawer/QueueNotice.js.map +1 -1
  33. package/dist/cjs/components/ChatDrawer/RecalledMemoriesWidget.js +17 -5
  34. package/dist/cjs/components/ChatDrawer/RecalledMemoriesWidget.js.map +1 -1
  35. package/dist/cjs/components/ChatDrawer/ReferenceChip.js +3 -1
  36. package/dist/cjs/components/ChatDrawer/ReferenceChip.js.map +1 -1
  37. package/dist/cjs/components/ChatDrawer/UsageBar.js +23 -18
  38. package/dist/cjs/components/ChatDrawer/UsageBar.js.map +1 -1
  39. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js +20 -9
  40. package/dist/cjs/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  41. package/dist/cjs/components/Feedback/FeedbackModal.js +5 -1
  42. package/dist/cjs/components/Feedback/FeedbackModal.js.map +1 -1
  43. package/dist/cjs/components/Feedback/MessageActions.js +3 -1
  44. package/dist/cjs/components/Feedback/MessageActions.js.map +1 -1
  45. package/dist/cjs/components/IntegrationsModal/ConnectFieldsForm.js +12 -8
  46. package/dist/cjs/components/IntegrationsModal/ConnectFieldsForm.js.map +1 -1
  47. package/dist/cjs/components/IntegrationsModal/IntegrationsHint.js +5 -3
  48. package/dist/cjs/components/IntegrationsModal/IntegrationsHint.js.map +1 -1
  49. package/dist/cjs/components/IntegrationsModal/IntegrationsLauncher.js +12 -3
  50. package/dist/cjs/components/IntegrationsModal/IntegrationsLauncher.js.map +1 -1
  51. package/dist/cjs/components/IntegrationsModal/IntegrationsPanel.js +34 -24
  52. package/dist/cjs/components/IntegrationsModal/IntegrationsPanel.js.map +1 -1
  53. package/dist/cjs/components/IntegrationsModal/IntegrationsToggle.js +15 -6
  54. package/dist/cjs/components/IntegrationsModal/IntegrationsToggle.js.map +1 -1
  55. package/dist/cjs/components/IntegrationsModal/McpConnectForm.js +15 -7
  56. package/dist/cjs/components/IntegrationsModal/McpConnectForm.js.map +1 -1
  57. package/dist/cjs/components/IntegrationsModal/McpServersSection.js +32 -19
  58. package/dist/cjs/components/IntegrationsModal/McpServersSection.js.map +1 -1
  59. package/dist/cjs/components/IntegrationsModal/useIntegrations.js +3 -1
  60. package/dist/cjs/components/IntegrationsModal/useIntegrations.js.map +1 -1
  61. package/dist/cjs/components/IntegrationsModal/useTenantMcp.js +3 -1
  62. package/dist/cjs/components/IntegrationsModal/useTenantMcp.js.map +1 -1
  63. package/dist/cjs/components/ThreadStateTag/ThreadStateTag.js +63 -40
  64. package/dist/cjs/components/ThreadStateTag/ThreadStateTag.js.map +1 -1
  65. package/dist/cjs/hooks/useDevicChat.js +11 -5
  66. package/dist/cjs/hooks/useDevicChat.js.map +1 -1
  67. package/dist/cjs/hooks/useSpeechRecording.js +8 -4
  68. package/dist/cjs/hooks/useSpeechRecording.js.map +1 -1
  69. package/dist/cjs/i18n/translate.js +48 -0
  70. package/dist/cjs/i18n/translate.js.map +1 -0
  71. package/dist/cjs/i18n/useTranslations.js +57 -0
  72. package/dist/cjs/i18n/useTranslations.js.map +1 -0
  73. package/dist/cjs/index.js +11 -0
  74. package/dist/cjs/index.js.map +1 -1
  75. package/dist/cjs/provider/DevicProvider.js +3 -1
  76. package/dist/cjs/provider/DevicProvider.js.map +1 -1
  77. package/dist/cjs/styles.css +1 -1
  78. package/dist/esm/api/types.d.ts +10 -1
  79. package/dist/esm/api/types.js.map +1 -1
  80. package/dist/esm/components/AICommandBar/AICommandBar.js +11 -8
  81. package/dist/esm/components/AICommandBar/AICommandBar.js.map +1 -1
  82. package/dist/esm/components/AICommandBar/AICommandBar.types.d.ts +10 -0
  83. package/dist/esm/components/AICommandBar/useAICommandBar.js +7 -5
  84. package/dist/esm/components/AICommandBar/useAICommandBar.js.map +1 -1
  85. package/dist/esm/components/AIElementWrapper/AIElementWrapper.js +17 -14
  86. package/dist/esm/components/AIElementWrapper/AIElementWrapper.js.map +1 -1
  87. package/dist/esm/components/AIElementWrapper/AIElementWrapper.types.d.ts +10 -0
  88. package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js +7 -5
  89. package/dist/esm/components/AIElementWrapper/useAIElementWrapper.js.map +1 -1
  90. package/dist/esm/components/AIGenerationButton/AIGenerationButton.js +12 -7
  91. package/dist/esm/components/AIGenerationButton/AIGenerationButton.js.map +1 -1
  92. package/dist/esm/components/AIGenerationButton/AIGenerationButton.types.d.ts +10 -0
  93. package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js +6 -4
  94. package/dist/esm/components/AIGenerationButton/useAIGenerationButton.js.map +1 -1
  95. package/dist/esm/components/ChatDrawer/ChatDrawer.js +27 -13
  96. package/dist/esm/components/ChatDrawer/ChatDrawer.js.map +1 -1
  97. package/dist/esm/components/ChatDrawer/ChatDrawer.types.d.ts +33 -0
  98. package/dist/esm/components/ChatDrawer/ChatInput.js +21 -15
  99. package/dist/esm/components/ChatDrawer/ChatInput.js.map +1 -1
  100. package/dist/esm/components/ChatDrawer/ChatMessages.d.ts +1 -1
  101. package/dist/esm/components/ChatDrawer/ChatMessages.js +54 -13
  102. package/dist/esm/components/ChatDrawer/ChatMessages.js.map +1 -1
  103. package/dist/esm/components/ChatDrawer/CompactionWidget.js +13 -4
  104. package/dist/esm/components/ChatDrawer/CompactionWidget.js.map +1 -1
  105. package/dist/esm/components/ChatDrawer/ConversationSelector.js +6 -4
  106. package/dist/esm/components/ChatDrawer/ConversationSelector.js.map +1 -1
  107. package/dist/esm/components/ChatDrawer/GuardrailNotice.d.ts +36 -0
  108. package/dist/esm/components/ChatDrawer/GuardrailNotice.js +38 -0
  109. package/dist/esm/components/ChatDrawer/GuardrailNotice.js.map +1 -0
  110. package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js +3 -1
  111. package/dist/esm/components/ChatDrawer/HandoffSubagentWidget.js.map +1 -1
  112. package/dist/esm/components/ChatDrawer/LimitBanner.js +19 -9
  113. package/dist/esm/components/ChatDrawer/LimitBanner.js.map +1 -1
  114. package/dist/esm/components/ChatDrawer/QueueNotice.js +19 -7
  115. package/dist/esm/components/ChatDrawer/QueueNotice.js.map +1 -1
  116. package/dist/esm/components/ChatDrawer/RecalledMemoriesWidget.js +17 -5
  117. package/dist/esm/components/ChatDrawer/RecalledMemoriesWidget.js.map +1 -1
  118. package/dist/esm/components/ChatDrawer/ReferenceChip.js +3 -1
  119. package/dist/esm/components/ChatDrawer/ReferenceChip.js.map +1 -1
  120. package/dist/esm/components/ChatDrawer/UsageBar.js +23 -18
  121. package/dist/esm/components/ChatDrawer/UsageBar.js.map +1 -1
  122. package/dist/esm/components/ChatDrawer/index.d.ts +2 -0
  123. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js +20 -9
  124. package/dist/esm/components/CoreMemoryModal/CoreMemoryModal.js.map +1 -1
  125. package/dist/esm/components/Feedback/FeedbackModal.js +5 -1
  126. package/dist/esm/components/Feedback/FeedbackModal.js.map +1 -1
  127. package/dist/esm/components/Feedback/MessageActions.js +3 -1
  128. package/dist/esm/components/Feedback/MessageActions.js.map +1 -1
  129. package/dist/esm/components/IntegrationsModal/ConnectFieldsForm.js +12 -8
  130. package/dist/esm/components/IntegrationsModal/ConnectFieldsForm.js.map +1 -1
  131. package/dist/esm/components/IntegrationsModal/IntegrationsHint.js +5 -3
  132. package/dist/esm/components/IntegrationsModal/IntegrationsHint.js.map +1 -1
  133. package/dist/esm/components/IntegrationsModal/IntegrationsLauncher.js +12 -3
  134. package/dist/esm/components/IntegrationsModal/IntegrationsLauncher.js.map +1 -1
  135. package/dist/esm/components/IntegrationsModal/IntegrationsPanel.d.ts +1 -1
  136. package/dist/esm/components/IntegrationsModal/IntegrationsPanel.js +34 -24
  137. package/dist/esm/components/IntegrationsModal/IntegrationsPanel.js.map +1 -1
  138. package/dist/esm/components/IntegrationsModal/IntegrationsToggle.d.ts +1 -1
  139. package/dist/esm/components/IntegrationsModal/IntegrationsToggle.js +15 -6
  140. package/dist/esm/components/IntegrationsModal/IntegrationsToggle.js.map +1 -1
  141. package/dist/esm/components/IntegrationsModal/McpConnectForm.js +15 -7
  142. package/dist/esm/components/IntegrationsModal/McpConnectForm.js.map +1 -1
  143. package/dist/esm/components/IntegrationsModal/McpServersSection.js +32 -19
  144. package/dist/esm/components/IntegrationsModal/McpServersSection.js.map +1 -1
  145. package/dist/esm/components/IntegrationsModal/useIntegrations.js +3 -1
  146. package/dist/esm/components/IntegrationsModal/useIntegrations.js.map +1 -1
  147. package/dist/esm/components/IntegrationsModal/useTenantMcp.js +3 -1
  148. package/dist/esm/components/IntegrationsModal/useTenantMcp.js.map +1 -1
  149. package/dist/esm/components/ThreadStateTag/ThreadStateTag.js +63 -40
  150. package/dist/esm/components/ThreadStateTag/ThreadStateTag.js.map +1 -1
  151. package/dist/esm/hooks/useDevicChat.js +12 -6
  152. package/dist/esm/hooks/useDevicChat.js.map +1 -1
  153. package/dist/esm/hooks/useSpeechRecording.js +8 -4
  154. package/dist/esm/hooks/useSpeechRecording.js.map +1 -1
  155. package/dist/esm/i18n/index.d.ts +4 -0
  156. package/dist/esm/i18n/translate.d.ts +23 -0
  157. package/dist/esm/i18n/translate.js +43 -0
  158. package/dist/esm/i18n/translate.js.map +1 -0
  159. package/dist/esm/i18n/types.d.ts +27 -0
  160. package/dist/esm/i18n/useTranslations.d.ts +32 -0
  161. package/dist/esm/i18n/useTranslations.js +53 -0
  162. package/dist/esm/i18n/useTranslations.js.map +1 -0
  163. package/dist/esm/index.d.ts +4 -2
  164. package/dist/esm/index.js +3 -0
  165. package/dist/esm/index.js.map +1 -1
  166. package/dist/esm/provider/DevicProvider.d.ts +1 -1
  167. package/dist/esm/provider/DevicProvider.js +3 -1
  168. package/dist/esm/provider/DevicProvider.js.map +1 -1
  169. package/dist/esm/provider/types.d.ts +33 -0
  170. package/dist/esm/styles.css +1 -1
  171. package/package.json +1 -1
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Replace `{name}` placeholders. A placeholder with no matching value is
3
+ * dropped rather than left in the text — half-substituted braces on screen
4
+ * read as a bug to the end user.
5
+ */
6
+ function fillTemplate(template, vars) {
7
+ if (!vars)
8
+ return template;
9
+ return template.replace(/\{(\w+)\}/g, (_, name) => {
10
+ const value = vars[name];
11
+ return value === undefined || value === null ? '' : String(value);
12
+ });
13
+ }
14
+ /**
15
+ * Look one English text up in the dictionary, then fill its placeholders.
16
+ * An absent entry falls back to the English text itself, so a partial
17
+ * dictionary is perfectly usable.
18
+ */
19
+ function translate(dictionary, text, vars) {
20
+ return fillTemplate(dictionary?.[text] ?? text, vars);
21
+ }
22
+ /**
23
+ * Build a translator bound to one dictionary. Stable for as long as the
24
+ * dictionary is, so it is safe in a dependency list.
25
+ */
26
+ function createTranslator(dictionary) {
27
+ return (text, vars) => translate(dictionary, text, vars);
28
+ }
29
+ /**
30
+ * Merge dictionaries, later ones winning. `undefined` layers are skipped so
31
+ * callers can pass optional ones straight in.
32
+ */
33
+ function mergeTranslations(...layers) {
34
+ const present = layers.filter(Boolean);
35
+ if (present.length === 0)
36
+ return undefined;
37
+ if (present.length === 1)
38
+ return present[0];
39
+ return Object.assign({}, ...present);
40
+ }
41
+
42
+ export { createTranslator, fillTemplate, mergeTranslations, translate };
43
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sources":["../../../src/i18n/translate.ts"],"sourcesContent":["import type { DevicTranslations, Translator } from './types';\n\n/**\n * Replace `{name}` placeholders. A placeholder with no matching value is\n * dropped rather than left in the text — half-substituted braces on screen\n * read as a bug to the end user.\n */\nexport function fillTemplate(\n template: string,\n vars?: Record<string, string | number>\n): string {\n if (!vars) return template;\n return template.replace(/\\{(\\w+)\\}/g, (_, name: string) => {\n const value = vars[name];\n return value === undefined || value === null ? '' : String(value);\n });\n}\n\n/**\n * Look one English text up in the dictionary, then fill its placeholders.\n * An absent entry falls back to the English text itself, so a partial\n * dictionary is perfectly usable.\n */\nexport function translate(\n dictionary: DevicTranslations | undefined,\n text: string,\n vars?: Record<string, string | number>\n): string {\n return fillTemplate(dictionary?.[text] ?? text, vars);\n}\n\n/**\n * Build a translator bound to one dictionary. Stable for as long as the\n * dictionary is, so it is safe in a dependency list.\n */\nexport function createTranslator(dictionary?: DevicTranslations): Translator {\n return (text, vars) => translate(dictionary, text, vars);\n}\n\n/**\n * Merge dictionaries, later ones winning. `undefined` layers are skipped so\n * callers can pass optional ones straight in.\n */\nexport function mergeTranslations(\n ...layers: (DevicTranslations | undefined)[]\n): DevicTranslations | undefined {\n const present = layers.filter(Boolean) as DevicTranslations[];\n if (present.length === 0) return undefined;\n if (present.length === 1) return present[0];\n return Object.assign({}, ...present) as DevicTranslations;\n}\n"],"names":[],"mappings":"AAEA;;;;AAIG;AACG,SAAU,YAAY,CAC1B,QAAgB,EAChB,IAAsC,EAAA;AAEtC,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,QAAQ;IAC1B,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,IAAY,KAAI;AACxD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;AACxB,QAAA,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;AACnE,IAAA,CAAC,CAAC;AACJ;AAEA;;;;AAIG;SACa,SAAS,CACvB,UAAyC,EACzC,IAAY,EACZ,IAAsC,EAAA;AAEtC,IAAA,OAAO,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC;AACvD;AAEA;;;AAGG;AACG,SAAU,gBAAgB,CAAC,UAA8B,EAAA;AAC7D,IAAA,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC;AAC1D;AAEA;;;AAGG;AACG,SAAU,iBAAiB,CAC/B,GAAG,MAAyC,EAAA;IAE5C,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAwB;AAC7D,IAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,SAAS;AAC1C,IAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,OAAO,CAAC,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,OAAO,CAAsB;AAC3D;;"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Dictionary of translations for the texts this library renders itself.
3
+ *
4
+ * The key is the exact English text the widget shows; the value is what to
5
+ * show instead. Nothing else is needed — no key catalogue to learn, and no
6
+ * i18n runtime bundled here: you keep whatever you already use (i18next,
7
+ * react-intl, a plain object per locale) and hand over the resulting strings.
8
+ *
9
+ * ```ts
10
+ * const translations = {
11
+ * 'New chat': 'Nueva conversación',
12
+ * 'Type a message...': 'Escribe un mensaje...',
13
+ * '{count} left': 'Quedan {count}',
14
+ * };
15
+ * ```
16
+ *
17
+ * A text that carries a `{name}` placeholder keeps it in the translation:
18
+ * placeholders are filled after the lookup, so they can be reordered or
19
+ * dropped freely. A text with no entry is shown in English.
20
+ */
21
+ export type DevicTranslations = Record<string, string>;
22
+ /**
23
+ * Resolves one English text to what should be rendered.
24
+ *
25
+ * `vars` fills the `{name}` placeholders of the result.
26
+ */
27
+ export type Translator = (text: string, vars?: Record<string, string | number>) => string;
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import type { DevicTranslations, Translator } from './types';
3
+ export interface DevicTranslationsProviderProps {
4
+ /** Entries added on top of the enclosing dictionaries. */
5
+ translations?: DevicTranslations;
6
+ children: React.ReactNode;
7
+ }
8
+ /**
9
+ * Scopes a dictionary to a subtree. Rarely needed directly — the components
10
+ * that take a `translations` option already wrap their own subtree with it —
11
+ * but useful to translate one region of a page differently.
12
+ */
13
+ export declare function DevicTranslationsProvider({ translations, children, }: DevicTranslationsProviderProps): JSX.Element;
14
+ /**
15
+ * The dictionary in force here: the provider's, plus any scoped by an
16
+ * enclosing component, plus the `local` argument. Later layers win.
17
+ */
18
+ export declare function useTranslationsDictionary(local?: DevicTranslations): DevicTranslations | undefined;
19
+ /**
20
+ * Returns `t`, the translator for every text this library renders itself.
21
+ *
22
+ * Works with or without a `DevicProvider`: with no dictionary anywhere it
23
+ * returns the English text unchanged, which is what a component mounted
24
+ * standalone gets.
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * const t = useTranslations();
29
+ * <button aria-label={t('New chat')}>…</button>
30
+ * ```
31
+ */
32
+ export declare function useTranslations(local?: DevicTranslations): Translator;
@@ -0,0 +1,53 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { createContext, useMemo, useContext } from 'react';
3
+ import { useOptionalDevicContext } from '../provider/DevicContext.js';
4
+ import { createTranslator, mergeTranslations } from './translate.js';
5
+
6
+ /**
7
+ * Dictionary contributed by an enclosing component, on top of the provider's.
8
+ *
9
+ * It exists so `<ChatDrawer options={{ translations }}>` reaches the input,
10
+ * the message list and the dialogs it opens without every one of them taking
11
+ * a prop for it. Nesting merges rather than replaces.
12
+ */
13
+ const TranslationsScope = createContext(undefined);
14
+ /**
15
+ * Scopes a dictionary to a subtree. Rarely needed directly — the components
16
+ * that take a `translations` option already wrap their own subtree with it —
17
+ * but useful to translate one region of a page differently.
18
+ */
19
+ function DevicTranslationsProvider({ translations, children, }) {
20
+ const outer = useContext(TranslationsScope);
21
+ const value = useMemo(() => mergeTranslations(outer, translations), [outer, translations]);
22
+ return (jsx(TranslationsScope.Provider, { value: value, children: children }));
23
+ }
24
+ /**
25
+ * The dictionary in force here: the provider's, plus any scoped by an
26
+ * enclosing component, plus the `local` argument. Later layers win.
27
+ */
28
+ function useTranslationsDictionary(local) {
29
+ const context = useOptionalDevicContext();
30
+ const scoped = useContext(TranslationsScope);
31
+ const global = context?.translations;
32
+ return useMemo(() => mergeTranslations(global, scoped, local), [global, scoped, local]);
33
+ }
34
+ /**
35
+ * Returns `t`, the translator for every text this library renders itself.
36
+ *
37
+ * Works with or without a `DevicProvider`: with no dictionary anywhere it
38
+ * returns the English text unchanged, which is what a component mounted
39
+ * standalone gets.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * const t = useTranslations();
44
+ * <button aria-label={t('New chat')}>…</button>
45
+ * ```
46
+ */
47
+ function useTranslations(local) {
48
+ const dictionary = useTranslationsDictionary(local);
49
+ return useMemo(() => createTranslator(dictionary), [dictionary]);
50
+ }
51
+
52
+ export { DevicTranslationsProvider, useTranslations, useTranslationsDictionary };
53
+ //# sourceMappingURL=useTranslations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslations.js","sources":["../../../src/i18n/useTranslations.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport { useOptionalDevicContext } from '../provider/DevicContext';\nimport { createTranslator, mergeTranslations } from './translate';\nimport type { DevicTranslations, Translator } from './types';\n\n/**\n * Dictionary contributed by an enclosing component, on top of the provider's.\n *\n * It exists so `<ChatDrawer options={{ translations }}>` reaches the input,\n * the message list and the dialogs it opens without every one of them taking\n * a prop for it. Nesting merges rather than replaces.\n */\nconst TranslationsScope = createContext<DevicTranslations | undefined>(undefined);\n\nexport interface DevicTranslationsProviderProps {\n /** Entries added on top of the enclosing dictionaries. */\n translations?: DevicTranslations;\n children: React.ReactNode;\n}\n\n/**\n * Scopes a dictionary to a subtree. Rarely needed directly — the components\n * that take a `translations` option already wrap their own subtree with it —\n * but useful to translate one region of a page differently.\n */\nexport function DevicTranslationsProvider({\n translations,\n children,\n}: DevicTranslationsProviderProps): JSX.Element {\n const outer = useContext(TranslationsScope);\n const value = useMemo(\n () => mergeTranslations(outer, translations),\n [outer, translations]\n );\n return (\n <TranslationsScope.Provider value={value}>\n {children}\n </TranslationsScope.Provider>\n );\n}\n\n/**\n * The dictionary in force here: the provider's, plus any scoped by an\n * enclosing component, plus the `local` argument. Later layers win.\n */\nexport function useTranslationsDictionary(\n local?: DevicTranslations\n): DevicTranslations | undefined {\n const context = useOptionalDevicContext();\n const scoped = useContext(TranslationsScope);\n const global = context?.translations;\n return useMemo(\n () => mergeTranslations(global, scoped, local),\n [global, scoped, local]\n );\n}\n\n/**\n * Returns `t`, the translator for every text this library renders itself.\n *\n * Works with or without a `DevicProvider`: with no dictionary anywhere it\n * returns the English text unchanged, which is what a component mounted\n * standalone gets.\n *\n * @example\n * ```tsx\n * const t = useTranslations();\n * <button aria-label={t('New chat')}>…</button>\n * ```\n */\nexport function useTranslations(local?: DevicTranslations): Translator {\n const dictionary = useTranslationsDictionary(local);\n return useMemo(() => createTranslator(dictionary), [dictionary]);\n}\n"],"names":["_jsx"],"mappings":";;;;;AAKA;;;;;;AAMG;AACH,MAAM,iBAAiB,GAAG,aAAa,CAAgC,SAAS,CAAC;AAQjF;;;;AAIG;SACa,yBAAyB,CAAC,EACxC,YAAY,EACZ,QAAQ,GACuB,EAAA;AAC/B,IAAA,MAAM,KAAK,GAAG,UAAU,CAAC,iBAAiB,CAAC;IAC3C,MAAM,KAAK,GAAG,OAAO,CACnB,MAAM,iBAAiB,CAAC,KAAK,EAAE,YAAY,CAAC,EAC5C,CAAC,KAAK,EAAE,YAAY,CAAC,CACtB;AACD,IAAA,QACEA,GAAA,CAAC,iBAAiB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EACrC,QAAQ,EAAA,CACkB;AAEjC;AAEA;;;AAGG;AACG,SAAU,yBAAyB,CACvC,KAAyB,EAAA;AAEzB,IAAA,MAAM,OAAO,GAAG,uBAAuB,EAAE;AACzC,IAAA,MAAM,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC;AAC5C,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,YAAY;IACpC,OAAO,OAAO,CACZ,MAAM,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAC9C,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CACxB;AACH;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,eAAe,CAAC,KAAyB,EAAA;AACvD,IAAA,MAAM,UAAU,GAAG,yBAAyB,CAAC,KAAK,CAAC;AACnD,IAAA,OAAO,OAAO,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;AAClE;;"}
@@ -1,7 +1,9 @@
1
1
  export { DevicProvider, DevicContext, useDevicContext, useOptionalDevicContext } from './provider';
2
2
  export type { DevicProviderConfig, DevicProviderProps, DevicContextValue, TenantMetadata, SubtenantMetadata, AIReference, DrawerRegistration, } from './provider';
3
- export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget, ReferenceChip, UsageBar, LimitBanner, QueueNotice, RecalledMemoriesWidget, CompactionWidget } from './components/ChatDrawer';
4
- export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, ReferenceChipProps, ReferenceChipVariant, SuggestedMessage, UsageBarProps, UsageBarDisplay, UsageBarData, LimitBannerProps, QueueNoticeProps, RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, CompactionWidgetProps, CompactionRenderer, CompactionRendererProps, } from './components/ChatDrawer';
3
+ export { DevicTranslationsProvider, useTranslations, useTranslationsDictionary, createTranslator, translate, mergeTranslations, fillTemplate, } from './i18n';
4
+ export type { DevicTranslations, Translator, DevicTranslationsProviderProps, } from './i18n';
5
+ export { ChatDrawer, ChatMessages, ChatInput, ToolTimeline, ConversationSelector, HandoffSubagentWidget, ReferenceChip, UsageBar, LimitBanner, QueueNotice, RecalledMemoriesWidget, CompactionWidget, GuardrailNotice } from './components/ChatDrawer';
6
+ export type { ChatDrawerProps, ChatDrawerOptions, ChatDrawerHandle, ChatMessagesProps, ChatInputProps, CustomPromptBoxProps, MessageBubbleRenderer, MessageBubbleRendererProps, ToolTimelineProps, AllowedFileTypes, ConversationSelectorProps, HandoffSubagentWidgetProps, ReferenceChipProps, ReferenceChipVariant, SuggestedMessage, UsageBarProps, UsageBarDisplay, UsageBarData, LimitBannerProps, QueueNoticeProps, RecalledMemoriesWidgetProps, RecalledMemoriesRenderer, RecalledMemoriesRendererProps, CompactionWidgetProps, CompactionRenderer, CompactionRendererProps, GuardrailNoticeProps, GuardrailRenderer, GuardrailPayload, } from './components/ChatDrawer';
5
7
  export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS } from './components/CoreMemoryModal';
6
8
  export type { CoreMemoryModalProps, CoreMemoryLabels } from './components/CoreMemoryModal';
7
9
  export { IntegrationsModal, IntegrationsPanel, IntegrationsLauncher, IntegrationsHint, IntegrationLogo, useIntegrations, McpServersSection, McpConnectForm, useTenantMcp, integrationChoiceKey, readIntegrationChoice, writeIntegrationChoice, pruneIntegrationChoice, } from './components/IntegrationsModal';
package/dist/esm/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  export { DevicProvider } from './provider/DevicProvider.js';
2
2
  export { DevicContext, useDevicContext, useOptionalDevicContext } from './provider/DevicContext.js';
3
+ export { DevicTranslationsProvider, useTranslations, useTranslationsDictionary } from './i18n/useTranslations.js';
4
+ export { createTranslator, fillTemplate, mergeTranslations, translate } from './i18n/translate.js';
3
5
  export { ChatDrawer } from './components/ChatDrawer/ChatDrawer.js';
4
6
  export { ChatMessages } from './components/ChatDrawer/ChatMessages.js';
5
7
  export { ChatInput } from './components/ChatDrawer/ChatInput.js';
@@ -12,6 +14,7 @@ export { LimitBanner } from './components/ChatDrawer/LimitBanner.js';
12
14
  export { QueueNotice } from './components/ChatDrawer/QueueNotice.js';
13
15
  export { RecalledMemoriesWidget } from './components/ChatDrawer/RecalledMemoriesWidget.js';
14
16
  export { CompactionWidget } from './components/ChatDrawer/CompactionWidget.js';
17
+ export { GuardrailNotice } from './components/ChatDrawer/GuardrailNotice.js';
15
18
  export { CoreMemoryModal, DEFAULT_CORE_MEMORY_LABELS } from './components/CoreMemoryModal/CoreMemoryModal.js';
16
19
  export { IntegrationsModal } from './components/IntegrationsModal/IntegrationsModal.js';
17
20
  export { IntegrationsPanel } from './components/IntegrationsModal/IntegrationsPanel.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -14,4 +14,4 @@ import type { DevicProviderProps } from './types';
14
14
  * </DevicProvider>
15
15
  * ```
16
16
  */
17
- export declare function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, pollingInterval, debug, children, }: DevicProviderProps): JSX.Element;
17
+ export declare function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, pollingInterval, translations, debug, children, }: DevicProviderProps): JSX.Element;
@@ -21,7 +21,7 @@ const DEFAULT_BASE_URL = 'https://api.devic.ai';
21
21
  * </DevicProvider>
22
22
  * ```
23
23
  */
24
- function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, pollingInterval, debug, children, }) {
24
+ function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl = DEFAULT_BASE_URL, tenantId, tenantMetadata, subtenantId, subtenantMetadata, tags, pollingInterval, translations, debug, children, }) {
25
25
  const [references, setReferences] = useState([]);
26
26
  const drawerRef = useRef(null);
27
27
  const addReference = useCallback((ref) => {
@@ -81,6 +81,7 @@ function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl = D
81
81
  subtenantMetadata,
82
82
  tags,
83
83
  pollingInterval,
84
+ translations,
84
85
  isConfigured: !!apiKey || usesSessions,
85
86
  debug,
86
87
  references,
@@ -102,6 +103,7 @@ function DevicProvider({ apiKey, getTenantSession, onSessionExpired, baseUrl = D
102
103
  subtenantMetadata,
103
104
  tags,
104
105
  pollingInterval,
106
+ translations,
105
107
  debug,
106
108
  references,
107
109
  addReference,
@@ -1 +1 @@
1
- {"version":3,"file":"DevicProvider.js","sources":["../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { createSharedSession } from './sharedSession';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n getTenantSession,\n onSessionExpired,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n // Both callbacks are read through a ref and handed on as stable wrappers.\n // An inline `getTenantSession={() => …}` is a new function on every render,\n // and passing it straight through would rebuild the client — throwing away\n // the session it holds, so the page fetches a token per render — and rebuild\n // the context, so every component below it would do the same.\n const sessionSourceRef = useRef(getTenantSession);\n sessionSourceRef.current = getTenantSession;\n const expiredRef = useRef(onSessionExpired);\n expiredRef.current = onSessionExpired;\n const usesSessions = !!getTenantSession;\n\n // One session for the whole tree: every component below builds its own API\n // client, and each dedupes only its own renewals — so without this, N clients\n // ask for N tokens. See `createSharedSession`.\n const tenantSession = useMemo(\n () =>\n usesSessions\n ? createSharedSession(() => sessionSourceRef.current!())\n : undefined,\n [usesSessions]\n );\n const sessionExpired = useMemo(() => () => expiredRef.current?.(), []);\n\n const client = useMemo(\n () =>\n new DevicApiClient({\n apiKey,\n baseUrl,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n }),\n [apiKey, baseUrl, tenantSession, sessionExpired]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n isConfigured: !!apiKey || usesSessions,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n tenantSession,\n sessionExpired,\n usesSessions,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"DevicProvider.js","sources":["../../../src/provider/DevicProvider.tsx"],"sourcesContent":["import React, { useMemo, useState, useRef, useCallback } from 'react';\nimport { DevicContext } from './DevicContext';\nimport { DevicApiClient } from '../api/client';\nimport { createSharedSession } from './sharedSession';\nimport { generateId } from '../utils';\nimport type {\n DevicProviderProps,\n DevicContextValue,\n AIReference,\n DrawerRegistration,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.devic.ai';\n\n/**\n * Provider component for Devic UI configuration\n *\n * @example\n * ```tsx\n * <DevicProvider\n * apiKey=\"devic-xxx\"\n * baseUrl=\"https://api.devic.ai\"\n * tenantId=\"tenant-123\"\n * tenantMetadata={{ userId: '456' }}\n * >\n * <App />\n * </DevicProvider>\n * ```\n */\nexport function DevicProvider({\n apiKey,\n getTenantSession,\n onSessionExpired,\n baseUrl = DEFAULT_BASE_URL,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n translations,\n debug,\n children,\n}: DevicProviderProps): JSX.Element {\n const [references, setReferences] = useState<AIReference[]>([]);\n const drawerRef = useRef<DrawerRegistration | null>(null);\n\n const addReference = useCallback((ref: Omit<AIReference, 'id'>): string => {\n const id = generateId();\n setReferences((prev) => [...prev, { ...ref, id }]);\n return id;\n }, []);\n\n const removeReference = useCallback((id: string) => {\n setReferences((prev) => prev.filter((r) => r.id !== id));\n }, []);\n\n const clearReferences = useCallback(() => {\n setReferences([]);\n }, []);\n\n const registerDrawer = useCallback((handle: DrawerRegistration) => {\n drawerRef.current = handle;\n return () => {\n if (drawerRef.current === handle) {\n drawerRef.current = null;\n }\n };\n }, []);\n\n const openDrawer = useCallback(() => {\n drawerRef.current?.open();\n }, []);\n\n // Both callbacks are read through a ref and handed on as stable wrappers.\n // An inline `getTenantSession={() => …}` is a new function on every render,\n // and passing it straight through would rebuild the client — throwing away\n // the session it holds, so the page fetches a token per render — and rebuild\n // the context, so every component below it would do the same.\n const sessionSourceRef = useRef(getTenantSession);\n sessionSourceRef.current = getTenantSession;\n const expiredRef = useRef(onSessionExpired);\n expiredRef.current = onSessionExpired;\n const usesSessions = !!getTenantSession;\n\n // One session for the whole tree: every component below builds its own API\n // client, and each dedupes only its own renewals — so without this, N clients\n // ask for N tokens. See `createSharedSession`.\n const tenantSession = useMemo(\n () =>\n usesSessions\n ? createSharedSession(() => sessionSourceRef.current!())\n : undefined,\n [usesSessions]\n );\n const sessionExpired = useMemo(() => () => expiredRef.current?.(), []);\n\n const client = useMemo(\n () =>\n new DevicApiClient({\n apiKey,\n baseUrl,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n }),\n [apiKey, baseUrl, tenantSession, sessionExpired]\n );\n\n const contextValue = useMemo<DevicContextValue>(\n () => ({\n client,\n apiKey,\n getTenantSession: tenantSession,\n onSessionExpired: sessionExpired,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n translations,\n isConfigured: !!apiKey || usesSessions,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n }),\n [\n client,\n apiKey,\n tenantSession,\n sessionExpired,\n usesSessions,\n baseUrl,\n tenantId,\n tenantMetadata,\n subtenantId,\n subtenantMetadata,\n tags,\n pollingInterval,\n translations,\n debug,\n references,\n addReference,\n removeReference,\n clearReferences,\n registerDrawer,\n openDrawer,\n ]\n );\n\n return (\n <DevicContext.Provider value={contextValue}>\n {children}\n </DevicContext.Provider>\n );\n}\n"],"names":["_jsx"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { DevicApiClient } from '../api/client';
2
+ import type { DevicTranslations } from '../i18n/types';
2
3
  /**
3
4
  * Tenant-level identity metadata sent to the Devic API. Used for per-tenant
4
5
  * cost attribution and to enrich the tenant record (name, contact, logo).
@@ -138,6 +139,33 @@ export interface DevicProviderConfig {
138
139
  * @default 1000
139
140
  */
140
141
  pollingInterval?: number;
142
+ /**
143
+ * Translations for the texts the library renders itself — the drawer
144
+ * header, the input placeholder, the buttons and tooltips of every widget.
145
+ *
146
+ * A plain `English text → your text` map, so the values come from whatever
147
+ * i18n system the host already runs (i18next, react-intl, a JSON per
148
+ * locale): nothing is looked up here beyond the key. Anything absent stays
149
+ * in English, so a partial dictionary is fine, and texts already
150
+ * configurable on their own (`welcomeMessage`, `inputPlaceholder`, …) keep
151
+ * winning over it.
152
+ *
153
+ * Texts with a `{name}` placeholder keep it in the translation; the
154
+ * placeholders are filled after the lookup, so they may be reordered.
155
+ *
156
+ * @example
157
+ * ```tsx
158
+ * <DevicProvider
159
+ * apiKey="devic-xxx"
160
+ * translations={{
161
+ * 'New chat': 'Nueva conversación',
162
+ * 'Type a message...': 'Escribe un mensaje...',
163
+ * 'Close chat': 'Cerrar el chat',
164
+ * }}
165
+ * >
166
+ * ```
167
+ */
168
+ translations?: DevicTranslations;
141
169
  /**
142
170
  * Enable debug logging to the browser console
143
171
  * @default false
@@ -219,6 +247,11 @@ export interface DevicContextValue {
219
247
  * integrator did not configure one, so each component keeps its own default.
220
248
  */
221
249
  pollingInterval?: number;
250
+ /**
251
+ * Translations for the texts the library renders itself, keyed by the
252
+ * English text. Undefined when the integrator configured none.
253
+ */
254
+ translations?: DevicTranslations;
222
255
  /**
223
256
  * Whether the provider is properly configured
224
257
  */