@aircall/ds 0.13.0 → 0.15.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 (34) hide show
  1. package/README.md +31 -0
  2. package/dist/globals.css +1 -1
  3. package/dist/index.d.ts +94 -33
  4. package/dist/index.js +292 -42
  5. package/package.json +16 -3
  6. package/skills/aircall-ds/migrate-icons/SKILL.md +346 -0
  7. package/skills/aircall-ds/migrate-tractor/SKILL.md +314 -0
  8. package/skills/aircall-ds/migrate-tractor/accordion/SKILL.md +276 -0
  9. package/skills/aircall-ds/migrate-tractor/alert/SKILL.md +225 -0
  10. package/skills/aircall-ds/migrate-tractor/avatar/SKILL.md +272 -0
  11. package/skills/aircall-ds/migrate-tractor/badge/SKILL.md +274 -0
  12. package/skills/aircall-ds/migrate-tractor/button/SKILL.md +277 -0
  13. package/skills/aircall-ds/migrate-tractor/card/SKILL.md +278 -0
  14. package/skills/aircall-ds/migrate-tractor/combobox/SKILL.md +346 -0
  15. package/skills/aircall-ds/migrate-tractor/data-table/SKILL.md +333 -0
  16. package/skills/aircall-ds/migrate-tractor/dialog/SKILL.md +206 -0
  17. package/skills/aircall-ds/migrate-tractor/divider/SKILL.md +226 -0
  18. package/skills/aircall-ds/migrate-tractor/dropdown-menu/SKILL.md +266 -0
  19. package/skills/aircall-ds/migrate-tractor/dropzone/SKILL.md +338 -0
  20. package/skills/aircall-ds/migrate-tractor/form-and-field/SKILL.md +325 -0
  21. package/skills/aircall-ds/migrate-tractor/gauge/SKILL.md +248 -0
  22. package/skills/aircall-ds/migrate-tractor/input/SKILL.md +261 -0
  23. package/skills/aircall-ds/migrate-tractor/item/SKILL.md +298 -0
  24. package/skills/aircall-ds/migrate-tractor/link/SKILL.md +263 -0
  25. package/skills/aircall-ds/migrate-tractor/popover/SKILL.md +214 -0
  26. package/skills/aircall-ds/migrate-tractor/select/SKILL.md +245 -0
  27. package/skills/aircall-ds/migrate-tractor/sheet-vs-drawer/SKILL.md +272 -0
  28. package/skills/aircall-ds/migrate-tractor/skeleton/SKILL.md +190 -0
  29. package/skills/aircall-ds/migrate-tractor/styling/SKILL.md +421 -0
  30. package/skills/aircall-ds/migrate-tractor/tabs/SKILL.md +250 -0
  31. package/skills/aircall-ds/migrate-tractor/toast/SKILL.md +322 -0
  32. package/skills/aircall-ds/migrate-tractor/tooltip/SKILL.md +204 -0
  33. package/skills/aircall-ds/migrate-tractor/tree/SKILL.md +346 -0
  34. package/skills/aircall-ds/setup/SKILL.md +347 -0
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { createContext, useContext } from "react";
2
+ import { createContext, useCallback, useContext, useSyncExternalStore } from "react";
3
3
  import { Accordion as Accordion$1 } from "@base-ui/react/accordion";
4
4
  import { clsx } from "clsx";
5
5
  import { extendTailwindMerge } from "tailwind-merge";
@@ -7,6 +7,7 @@ import { ArrowDownToLine, ArrowLeft, ArrowRight, CheckIcon, ChevronDownIcon, Che
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Button as Button$1 } from "@base-ui/react/button";
9
9
  import { cva } from "class-variance-authority";
10
+ import i18next from "i18next";
10
11
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
11
12
  import { Avatar as Avatar$1 } from "@base-ui/react/avatar";
12
13
  import { mergeProps } from "@base-ui/react/merge-props";
@@ -209,6 +210,194 @@ const Button = React.forwardRef((componentProps, forwardRef) => {
209
210
  });
210
211
  Button.displayName = "Button";
211
212
 
213
+ //#endregion
214
+ //#region src/i18n/locales/de.ts
215
+ const de = {
216
+ "spinner.loading": "Laden",
217
+ "pagination.label": "Seitennavigation",
218
+ "pagination.previousPage": "Zur vorherigen Seite",
219
+ "pagination.nextPage": "Zur nächsten Seite",
220
+ "dataTable.selectAllRows": "Alle Zeilen auswählen",
221
+ "dataTable.selectRow": "Zeile auswählen",
222
+ "tree.collapse": "Minimieren",
223
+ "tree.expand": "Erweitern",
224
+ "multiselect.remove": "Entfernen",
225
+ "multiselect.clearAll": "Alles löschen",
226
+ "sidebar.toggle": "Seitenleiste umschalten",
227
+ "drawer.close": "Schließen",
228
+ "emojiPicker.emoji": "Emoji",
229
+ "emojiPicker.choose": "Emoji auswählen",
230
+ "actionBar.selectionActions": "Auswahlaktionen",
231
+ "pagination.previous": "Zurück",
232
+ "pagination.next": "Weiter",
233
+ "actionBar.clearSelection": "Auswahl aufheben",
234
+ "actionBar.itemsSelected": "{{count}} Elemente ausgewählt."
235
+ };
236
+ var de_default = de;
237
+
238
+ //#endregion
239
+ //#region src/i18n/locales/en.ts
240
+ const en = {
241
+ "spinner.loading": "Loading",
242
+ "pagination.label": "pagination",
243
+ "pagination.previousPage": "Go to previous page",
244
+ "pagination.nextPage": "Go to next page",
245
+ "dataTable.selectAllRows": "Select all rows",
246
+ "dataTable.selectRow": "Select row",
247
+ "tree.collapse": "Collapse",
248
+ "tree.expand": "Expand",
249
+ "multiselect.remove": "Remove",
250
+ "multiselect.clearAll": "Clear all",
251
+ "sidebar.toggle": "Toggle Sidebar",
252
+ "drawer.close": "Close",
253
+ "emojiPicker.emoji": "Emoji",
254
+ "emojiPicker.choose": "Choose an emoji",
255
+ "actionBar.selectionActions": "Selection actions",
256
+ "pagination.previous": "Previous",
257
+ "pagination.next": "Next",
258
+ "actionBar.clearSelection": "Clear selection",
259
+ "actionBar.itemsSelected": "{{count}} items selected."
260
+ };
261
+ var en_default = en;
262
+
263
+ //#endregion
264
+ //#region src/i18n/locales/es.ts
265
+ const es = {
266
+ "spinner.loading": "Cargando",
267
+ "pagination.label": "paginación",
268
+ "pagination.previousPage": "Ir a la página anterior",
269
+ "pagination.nextPage": "Ir a la página siguiente",
270
+ "dataTable.selectAllRows": "Seleccionar todas las filas",
271
+ "dataTable.selectRow": "Seleccionar fila",
272
+ "tree.collapse": "Minimizar",
273
+ "tree.expand": "Ampliar",
274
+ "multiselect.remove": "Eliminar",
275
+ "multiselect.clearAll": "Borrar todo",
276
+ "sidebar.toggle": "Alternar barra lateral",
277
+ "drawer.close": "Cerrar",
278
+ "emojiPicker.emoji": "Emoji",
279
+ "emojiPicker.choose": "Elegir un emoji",
280
+ "actionBar.selectionActions": "Acciones de selección",
281
+ "pagination.previous": "Anterior",
282
+ "pagination.next": "Siguiente",
283
+ "actionBar.clearSelection": "Borrar selección",
284
+ "actionBar.itemsSelected": "{{count}} elementos seleccionados."
285
+ };
286
+ var es_default = es;
287
+
288
+ //#endregion
289
+ //#region src/i18n/locales/fr.ts
290
+ const fr = {
291
+ "spinner.loading": "Chargement",
292
+ "pagination.label": "pagination",
293
+ "pagination.previousPage": "Aller à la page précédente",
294
+ "pagination.nextPage": "Aller à la page suivante",
295
+ "dataTable.selectAllRows": "Sélectionner toutes les lignes",
296
+ "dataTable.selectRow": "Sélectionner la ligne",
297
+ "tree.collapse": "Réduire",
298
+ "tree.expand": "Développer",
299
+ "multiselect.remove": "Supprimer",
300
+ "multiselect.clearAll": "Tout effacer",
301
+ "sidebar.toggle": "Basculer la barre latérale",
302
+ "drawer.close": "Fermer",
303
+ "emojiPicker.emoji": "Émoji",
304
+ "emojiPicker.choose": "Choisir un émoji",
305
+ "actionBar.selectionActions": "Actions de sélection",
306
+ "pagination.previous": "Précédent",
307
+ "pagination.next": "Suivant",
308
+ "actionBar.clearSelection": "Effacer la sélection",
309
+ "actionBar.itemsSelected": "{{count}} éléments sélectionnés."
310
+ };
311
+ var fr_default = fr;
312
+
313
+ //#endregion
314
+ //#region src/i18n/locales/it.ts
315
+ const it = {
316
+ "spinner.loading": "Caricamento",
317
+ "pagination.label": "paginazione",
318
+ "pagination.nextPage": "Vai alla pagina successiva",
319
+ "pagination.previousPage": "Vai alla pagina precedente",
320
+ "dataTable.selectAllRows": "Seleziona tutte le righe",
321
+ "dataTable.selectRow": "Seleziona riga",
322
+ "tree.collapse": "Ridurre",
323
+ "tree.expand": "Espandi",
324
+ "multiselect.remove": "Rimuovi",
325
+ "multiselect.clearAll": "Cancella tutto",
326
+ "sidebar.toggle": "Attiva/disattiva barra laterale",
327
+ "drawer.close": "Chiudi",
328
+ "emojiPicker.emoji": "Emoji",
329
+ "emojiPicker.choose": "Scegli un emoji",
330
+ "actionBar.selectionActions": "Azioni di selezione",
331
+ "pagination.previous": "Precedente",
332
+ "pagination.next": "Successivo",
333
+ "actionBar.clearSelection": "Cancella selezione",
334
+ "actionBar.itemsSelected": "{{count}} elementi selezionati."
335
+ };
336
+ var it_default = it;
337
+
338
+ //#endregion
339
+ //#region src/i18n/instance.ts
340
+ const SUPPORTED_LANGUAGES = [
341
+ "en",
342
+ "fr",
343
+ "es",
344
+ "de",
345
+ "it"
346
+ ];
347
+ const FALLBACK_LANGUAGE = "en";
348
+ /** Resolve the initial language from the environment, falling back to English. */
349
+ function detectInitialLanguage() {
350
+ if (typeof navigator === "undefined" || !navigator.language) return FALLBACK_LANGUAGE;
351
+ const base = navigator.language.split("-")[0];
352
+ return SUPPORTED_LANGUAGES.includes(base) ? base : FALLBACK_LANGUAGE;
353
+ }
354
+ /** The single private i18next instance owned by @aircall/ds. Isolated from any consumer instance. */
355
+ const dsI18n = i18next.createInstance();
356
+ dsI18n.init({
357
+ lng: detectInitialLanguage(),
358
+ fallbackLng: FALLBACK_LANGUAGE,
359
+ supportedLngs: [...SUPPORTED_LANGUAGES],
360
+ load: "languageOnly",
361
+ ns: ["ds"],
362
+ defaultNS: "ds",
363
+ resources: {
364
+ en: { ds: en_default },
365
+ fr: { ds: fr_default },
366
+ es: { ds: es_default },
367
+ de: { ds: de_default },
368
+ it: { ds: it_default }
369
+ },
370
+ interpolation: { escapeValue: false },
371
+ keySeparator: false,
372
+ returnNull: false,
373
+ initImmediate: false
374
+ });
375
+ /** Register an additional namespace's resources into the shared instance (used by @aircall/blocks). */
376
+ function registerI18nNamespace(ns, resources) {
377
+ for (const [lng, bundle] of Object.entries(resources)) dsI18n.addResourceBundle(lng, ns, bundle, true, true);
378
+ }
379
+
380
+ //#endregion
381
+ //#region src/i18n/use-ds-translation.ts
382
+ function subscribe(onChange) {
383
+ dsI18n.on("languageChanged", onChange);
384
+ return () => dsI18n.off("languageChanged", onChange);
385
+ }
386
+ function getLanguageSnapshot() {
387
+ return dsI18n.language;
388
+ }
389
+ /**
390
+ * @internal
391
+ * Reads translations from the shared ds instance and re-renders on language change.
392
+ * Used by @aircall/ds and @aircall/blocks components only — not part of the consumer contract.
393
+ */
394
+ function useDsTranslation(ns) {
395
+ return useCallback((key, opts) => dsI18n.t(key, {
396
+ ns,
397
+ ...opts
398
+ }), [ns, useSyncExternalStore(subscribe, getLanguageSnapshot, getLanguageSnapshot)]);
399
+ }
400
+
212
401
  //#endregion
213
402
  //#region src/components/action-bar.tsx
214
403
  /** Fixed height of the ActionBar (px). Single source of truth — the bar uses it
@@ -232,14 +421,16 @@ const ActionBarButton = React.forwardRef((componentProps, forwardRef) => {
232
421
  });
233
422
  ActionBarButton.displayName = "ActionBarButton";
234
423
  const ActionBar = React.forwardRef((componentProps, forwardRef) => {
235
- const { className, count, onClear, children, label, clearLabel = "Clear selection", style, ...props } = componentProps;
424
+ const { className, count, onClear, children, label, clearLabel, style, ...props } = componentProps;
425
+ const t = useDsTranslation("ds");
236
426
  const ctx = React.useContext(ActionBarContext);
237
427
  const resolvedCount = count ?? ctx?.count ?? 0;
238
428
  const resolvedOnClear = onClear ?? ctx?.onClear;
429
+ const resolvedClearLabel = clearLabel ?? t("actionBar.clearSelection");
239
430
  return /* @__PURE__ */ jsxs("div", {
240
431
  ref: forwardRef,
241
432
  role: "toolbar",
242
- "aria-label": "Selection actions",
433
+ "aria-label": t("actionBar.selectionActions"),
243
434
  "data-slot": "action-bar",
244
435
  className: cn("relative flex w-full items-center gap-2 rounded-md border border-border bg-popover px-2 text-popover-foreground shadow-lg", className),
245
436
  style: {
@@ -251,12 +442,12 @@ const ActionBar = React.forwardRef((componentProps, forwardRef) => {
251
442
  resolvedOnClear ? /* @__PURE__ */ jsx(ActionBarButton, {
252
443
  size: "icon",
253
444
  onClick: resolvedOnClear,
254
- "aria-label": clearLabel,
445
+ "aria-label": resolvedClearLabel,
255
446
  children: /* @__PURE__ */ jsx(XIcon, {})
256
447
  }) : null,
257
448
  /* @__PURE__ */ jsx("span", {
258
449
  className: "flex-1 truncate text-sm",
259
- children: label ? label(resolvedCount) : `${resolvedCount} items selected.`
450
+ children: label ? label(resolvedCount) : t("actionBar.itemsSelected", { count: resolvedCount })
260
451
  }),
261
452
  children ? /* @__PURE__ */ jsx("div", {
262
453
  className: "flex shrink-0 items-center gap-2",
@@ -2217,11 +2408,12 @@ const spinnerVariants = cva("animate-spin text-current", {
2217
2408
  });
2218
2409
  const Spinner = React.forwardRef((componentProps, forwardRef) => {
2219
2410
  const { className, size, ...props } = componentProps;
2411
+ const t = useDsTranslation("ds");
2220
2412
  return /* @__PURE__ */ jsx(Loader2Icon, {
2221
2413
  ref: forwardRef,
2222
2414
  "data-slot": "spinner",
2223
2415
  role: "status",
2224
- "aria-label": "Loading",
2416
+ "aria-label": t("spinner.loading"),
2225
2417
  className: cn(spinnerVariants({ size }), className),
2226
2418
  ...props
2227
2419
  });
@@ -2239,7 +2431,7 @@ const Table = React.forwardRef((componentProps, forwardRef) => {
2239
2431
  children: /* @__PURE__ */ jsx("table", {
2240
2432
  ref: forwardRef,
2241
2433
  "data-slot": "table",
2242
- className: cn("w-full caption-bottom text-sm [&_tbody_tr:last-child]:border-b-0", className),
2434
+ className: cn("w-full caption-bottom text-sm text-foreground [&_tbody_tr:last-child]:border-b-0", className),
2243
2435
  ...props
2244
2436
  })
2245
2437
  });
@@ -2448,29 +2640,35 @@ function DataTable(componentProps) {
2448
2640
  ]
2449
2641
  });
2450
2642
  }
2643
+ function SelectAllHeader({ table }) {
2644
+ const t = useDsTranslation("ds");
2645
+ const allSelected = table.getIsAllRowsSelected();
2646
+ const someSelected = table.getIsSomeRowsSelected();
2647
+ return /* @__PURE__ */ jsx(Checkbox, {
2648
+ checked: allSelected,
2649
+ indeterminate: !allSelected && someSelected,
2650
+ onCheckedChange: (value) => table.toggleAllRowsSelected(value === true),
2651
+ "aria-label": t("dataTable.selectAllRows")
2652
+ });
2653
+ }
2654
+ function SelectRowCell({ row }) {
2655
+ const t = useDsTranslation("ds");
2656
+ return /* @__PURE__ */ jsx("span", {
2657
+ className: "contents",
2658
+ onClick: (e) => e.stopPropagation(),
2659
+ children: /* @__PURE__ */ jsx(Checkbox, {
2660
+ checked: row.getIsSelected(),
2661
+ disabled: !row.getCanSelect(),
2662
+ onCheckedChange: (value) => row.toggleSelected(value === true),
2663
+ "aria-label": t("dataTable.selectRow")
2664
+ })
2665
+ });
2666
+ }
2451
2667
  function makeSelectColumn() {
2452
2668
  return {
2453
2669
  id: SELECT_COLUMN_ID,
2454
- header: ({ table }) => {
2455
- const allSelected = table.getIsAllRowsSelected();
2456
- const someSelected = table.getIsSomeRowsSelected();
2457
- return /* @__PURE__ */ jsx(Checkbox, {
2458
- checked: allSelected,
2459
- indeterminate: !allSelected && someSelected,
2460
- onCheckedChange: (value) => table.toggleAllRowsSelected(value === true),
2461
- "aria-label": "Select all rows"
2462
- });
2463
- },
2464
- cell: ({ row }) => /* @__PURE__ */ jsx("span", {
2465
- className: "contents",
2466
- onClick: (e) => e.stopPropagation(),
2467
- children: /* @__PURE__ */ jsx(Checkbox, {
2468
- checked: row.getIsSelected(),
2469
- disabled: !row.getCanSelect(),
2470
- onCheckedChange: (value) => row.toggleSelected(value === true),
2471
- "aria-label": "Select row"
2472
- })
2473
- }),
2670
+ header: ({ table }) => /* @__PURE__ */ jsx(SelectAllHeader, { table }),
2671
+ cell: ({ row }) => /* @__PURE__ */ jsx(SelectRowCell, { row }),
2474
2672
  enableSorting: false,
2475
2673
  enableHiding: false,
2476
2674
  enableResizing: false,
@@ -2644,6 +2842,7 @@ function TreeItem({ item, className, children, onActivate, onClick: userOnClick,
2644
2842
  }
2645
2843
  function TreeItemLabel({ item: propItem, children, className, ...props }) {
2646
2844
  const { currentItem } = useTreeContext();
2845
+ const t = useDsTranslation("ds");
2647
2846
  const item = propItem || currentItem;
2648
2847
  if (!item) {
2649
2848
  console.warn("TreeItemLabel: No item provided via props or context");
@@ -2656,7 +2855,7 @@ function TreeItemLabel({ item: propItem, children, className, ...props }) {
2656
2855
  "data-slot": "tree-item-label",
2657
2856
  ...props,
2658
2857
  children: [isFolder ? /* @__PURE__ */ jsx(Button, {
2659
- "aria-label": isExpanded ? "Collapse" : "Expand",
2858
+ "aria-label": isExpanded ? t("tree.collapse") : t("tree.expand"),
2660
2859
  className: "shrink-0 text-muted-foreground",
2661
2860
  onClick: (event) => {
2662
2861
  event.stopPropagation();
@@ -2873,6 +3072,7 @@ const DrawerViewport = React.forwardRef((componentProps, forwardRef) => {
2873
3072
  DrawerViewport.displayName = "DrawerViewport";
2874
3073
  const DrawerPopup = React.forwardRef((componentProps, forwardRef) => {
2875
3074
  const { className, children, showCloseButton = false, position: positionProp, variant = "default", showBar = false, container, ...props } = componentProps;
3075
+ const t = useDsTranslation("ds");
2876
3076
  const { position: contextPosition } = useContext(DrawerContext);
2877
3077
  const position = positionProp ?? contextPosition;
2878
3078
  const inContainer = !!container;
@@ -2890,7 +3090,7 @@ const DrawerPopup = React.forwardRef((componentProps, forwardRef) => {
2890
3090
  children: [
2891
3091
  children,
2892
3092
  showCloseButton && /* @__PURE__ */ jsx(DrawerPrimitive.Close, {
2893
- "aria-label": "Close",
3093
+ "aria-label": t("drawer.close"),
2894
3094
  className: "absolute end-2 top-2",
2895
3095
  render: /* @__PURE__ */ jsx(Button, {
2896
3096
  size: "icon",
@@ -3812,9 +4012,10 @@ function EmojiPicker({ onEmojiSelect, children }) {
3812
4012
  }
3813
4013
  const EmojiPickerTrigger = React.forwardRef((componentProps, forwardRef) => {
3814
4014
  const { render, children, ...props } = componentProps;
4015
+ const t = useDsTranslation("ds");
3815
4016
  return /* @__PURE__ */ jsx(PopoverTrigger, {
3816
4017
  ref: forwardRef,
3817
- "aria-label": "Emoji",
4018
+ "aria-label": t("emojiPicker.emoji"),
3818
4019
  render: render ?? /* @__PURE__ */ jsx(Button, {
3819
4020
  variant: "outline",
3820
4021
  size: "icon"
@@ -3827,10 +4028,11 @@ EmojiPickerTrigger.displayName = "EmojiPickerTrigger";
3827
4028
  function EmojiPickerContent({ className, align = "start", searchPlaceholder, categories, width = 300, suggestedEmojisMode = SuggestionMode.RECENT, ...props }) {
3828
4029
  const { onSelect } = useEmojiPickerContext();
3829
4030
  const { resolvedTheme } = useTheme();
4031
+ const t = useDsTranslation("ds");
3830
4032
  const pickerTheme = resolvedTheme === "dark" ? Theme.DARK : Theme.LIGHT;
3831
4033
  const handleClick = React.useCallback((emojiData) => onSelect(emojiData.emoji), [onSelect]);
3832
4034
  return /* @__PURE__ */ jsx(PopoverContent, {
3833
- "aria-label": "Choose an emoji",
4035
+ "aria-label": t("emojiPicker.choose"),
3834
4036
  className: cn("p-0 w-auto overflow-hidden ring-foreground/5", className),
3835
4037
  align,
3836
4038
  ...props,
@@ -4305,10 +4507,11 @@ ListCol.displayName = "ListCol";
4305
4507
  //#region src/components/pagination.tsx
4306
4508
  const Pagination = React.forwardRef((componentProps, forwardRef) => {
4307
4509
  const { className, ...props } = componentProps;
4510
+ const t = useDsTranslation("ds");
4308
4511
  return /* @__PURE__ */ jsx("nav", {
4309
4512
  ref: forwardRef,
4310
4513
  role: "navigation",
4311
- "aria-label": "pagination",
4514
+ "aria-label": t("pagination.label"),
4312
4515
  "data-slot": "pagination",
4313
4516
  className: cn("mx-auto flex w-full justify-center", className),
4314
4517
  ...props
@@ -4352,31 +4555,35 @@ const PaginationLink = React.forwardRef((componentProps, forwardRef) => {
4352
4555
  });
4353
4556
  PaginationLink.displayName = "PaginationLink";
4354
4557
  const PaginationPrevious = React.forwardRef((componentProps, forwardRef) => {
4355
- const { className, text = "Previous", ...props } = componentProps;
4558
+ const { className, text, ...props } = componentProps;
4559
+ const t = useDsTranslation("ds");
4560
+ const resolvedText = text ?? t("pagination.previous");
4356
4561
  return /* @__PURE__ */ jsxs(PaginationLink, {
4357
4562
  ref: forwardRef,
4358
- "aria-label": "Go to previous page",
4563
+ "aria-label": t("pagination.previousPage"),
4359
4564
  size: "default",
4360
4565
  className: cn("pl-2!", className),
4361
4566
  ...props,
4362
4567
  children: [/* @__PURE__ */ jsx(ChevronLeftIcon, { "data-icon": "inline-start" }), /* @__PURE__ */ jsx("span", {
4363
4568
  className: "hidden sm:block",
4364
- children: text
4569
+ children: resolvedText
4365
4570
  })]
4366
4571
  });
4367
4572
  });
4368
4573
  PaginationPrevious.displayName = "PaginationPrevious";
4369
4574
  const PaginationNext = React.forwardRef((componentProps, forwardRef) => {
4370
- const { className, text = "Next", ...props } = componentProps;
4575
+ const { className, text, ...props } = componentProps;
4576
+ const t = useDsTranslation("ds");
4577
+ const resolvedText = text ?? t("pagination.next");
4371
4578
  return /* @__PURE__ */ jsxs(PaginationLink, {
4372
4579
  ref: forwardRef,
4373
- "aria-label": "Go to next page",
4580
+ "aria-label": t("pagination.nextPage"),
4374
4581
  size: "default",
4375
4582
  className: cn("pr-2!", className),
4376
4583
  ...props,
4377
4584
  children: [/* @__PURE__ */ jsx("span", {
4378
4585
  className: "hidden sm:block",
4379
- children: text
4586
+ children: resolvedText
4380
4587
  }), /* @__PURE__ */ jsx(ChevronRightIcon, { "data-icon": "inline-end" })]
4381
4588
  });
4382
4589
  });
@@ -4914,6 +5121,7 @@ Sidebar.displayName = "Sidebar";
4914
5121
  const SidebarTrigger = React.forwardRef((componentProps, forwardRef) => {
4915
5122
  const { className, onClick, ...props } = componentProps;
4916
5123
  const { toggleSidebar } = useSidebar();
5124
+ const t = useDsTranslation("ds");
4917
5125
  return /* @__PURE__ */ jsxs(Button, {
4918
5126
  ref: forwardRef,
4919
5127
  "data-sidebar": "trigger",
@@ -4928,7 +5136,7 @@ const SidebarTrigger = React.forwardRef((componentProps, forwardRef) => {
4928
5136
  ...props,
4929
5137
  children: [/* @__PURE__ */ jsx(PanelLeftIcon, {}), /* @__PURE__ */ jsx("span", {
4930
5138
  className: "sr-only",
4931
- children: "Toggle Sidebar"
5139
+ children: t("sidebar.toggle")
4932
5140
  })]
4933
5141
  });
4934
5142
  });
@@ -4936,14 +5144,15 @@ SidebarTrigger.displayName = "SidebarTrigger";
4936
5144
  const SidebarRail = React.forwardRef((componentProps, forwardRef) => {
4937
5145
  const { className, ...props } = componentProps;
4938
5146
  const { toggleSidebar } = useSidebar();
5147
+ const t = useDsTranslation("ds");
4939
5148
  return /* @__PURE__ */ jsx("button", {
4940
5149
  ref: forwardRef,
4941
5150
  "data-sidebar": "rail",
4942
5151
  "data-slot": "sidebar-rail",
4943
- "aria-label": "Toggle Sidebar",
5152
+ "aria-label": t("sidebar.toggle"),
4944
5153
  tabIndex: -1,
4945
5154
  onClick: toggleSidebar,
4946
- title: "Toggle Sidebar",
5155
+ title: t("sidebar.toggle"),
4947
5156
  className: cn("absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar", "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", className),
4948
5157
  ...props
4949
5158
  });
@@ -5566,6 +5775,47 @@ const ToggleGroupItem = React.forwardRef((componentProps, forwardRef) => {
5566
5775
  });
5567
5776
  ToggleGroupItem.displayName = "ToggleGroupItem";
5568
5777
 
5778
+ //#endregion
5779
+ //#region src/components/ds-i18n-provider.tsx
5780
+ /**
5781
+ * Drives the language of the shared `dsI18n` singleton from React.
5782
+ *
5783
+ * PRODUCTION INVARIANT — mount EXACTLY ONE `DsI18nProvider` at the app root, as an
5784
+ * ancestor of all DS components. This is NOT a context provider: it mutates the single
5785
+ * shared `dsI18n` singleton inside an effect. Therefore NEVER nest two providers with
5786
+ * differing languages — they are competing singleton mutators, and because React runs
5787
+ * effects inside-out, the OUTERMOST provider's effect runs last and wins, silently
5788
+ * overriding the inner one. DS apps are single-locale, so one root provider is correct.
5789
+ *
5790
+ * Use either `DsI18nProvider` (React apps) OR `syncDsLanguage` (non-React startup) — not
5791
+ * both, for the same reason: each mutates the same singleton and they would compete.
5792
+ */
5793
+ function DsI18nProvider(componentProps) {
5794
+ const { language, children } = componentProps;
5795
+ React.useEffect(() => {
5796
+ const target = language ?? detectInitialLanguage();
5797
+ if (dsI18n.language !== target) dsI18n.changeLanguage(target);
5798
+ }, [language]);
5799
+ return children;
5800
+ }
5801
+ /**
5802
+ * Escape hatch for non-React / global-instance startup (e.g. the browser extension).
5803
+ * Mirrors `instance`'s current language onto the ds instance and follows its changes.
5804
+ * Returns an unsubscribe function.
5805
+ *
5806
+ * PRODUCTION INVARIANT — call this OR mount `DsI18nProvider`, never both. Both mutate the
5807
+ * same `dsI18n` singleton, so running them together makes them compete (last writer wins).
5808
+ * Like the provider, the singleton is single-locale: drive it from exactly one source.
5809
+ */
5810
+ function syncDsLanguage(instance) {
5811
+ if (instance.language && dsI18n.language !== instance.language) dsI18n.changeLanguage(instance.language);
5812
+ const handler = (lng) => {
5813
+ dsI18n.changeLanguage(lng);
5814
+ };
5815
+ instance.on("languageChanged", handler);
5816
+ return () => instance.off("languageChanged", handler);
5817
+ }
5818
+
5569
5819
  //#endregion
5570
5820
  //#region src/hooks/use-audio-gauge.ts
5571
5821
  /**
@@ -5641,4 +5891,4 @@ function useAudioGauge(options = {}) {
5641
5891
  }
5642
5892
 
5643
5893
  //#endregion
5644
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActionBar, ActionBarButton, ActionBarContext, ActionBarHeight, Alert, AlertAction, AlertAction as BannerAction, AlertDescription, AlertDescription as BannerDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AlertTitle as BannerTitle, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BadgeGroup, BadgeGroupCount, Banner, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, Chip, ChipRemove, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CounterBadge, CountryFlag, DataTable, DataTree, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerBackdrop, DrawerBar, DrawerClose, DrawerContent, DrawerCreateHandle, DrawerDescription, DrawerFooter, DrawerHeader, DrawerMenu, DrawerMenuCheckboxItem, DrawerMenuGroup, DrawerMenuGroupLabel, DrawerMenuItem, DrawerMenuRadioGroup, DrawerMenuRadioItem, DrawerMenuSeparator, DrawerMenuTrigger, DrawerPanel, DrawerPopup, DrawerPortal, DrawerPrimitive, DrawerSwipeArea, DrawerTitle, DrawerTrigger, DrawerViewport, DropdownMenu, DropdownMenuAddon, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, DropzoneActions, DropzoneContent, DropzoneDescription, DropzoneIcon, DropzoneTitle, DropzoneTrigger, EmojiPicker, EmojiPickerCategories, EmojiPickerContent, EmojiPickerTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FAB, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Filter, FilterClearAllButton, FilterGroup, Gauge, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Label, List, ListCol, ListRow, NotificationQueueProvider, NotificationSlot, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, ScrollArea, ScrollAreaPrimitive, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Stepper, StepperContent, StepperCounter, StepperPanel, StepperProgress, Switch, Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tree, TreeDragLine, TreeItem, TreeItemLabel, alertVariants, bannerVariants, buttonGroupVariants, buttonVariants, cn, counterBadgeVariants, fabVariants, selectTriggerVariants, spinnerVariants, toast, toggleVariants, useAudioGauge, useComboboxAnchor, useNotification, useNotificationQueue, useSidebar, useStepper, useTheme };
5894
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActionBar, ActionBarButton, ActionBarContext, ActionBarHeight, Alert, AlertAction, AlertAction as BannerAction, AlertDescription, AlertDescription as BannerDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AlertTitle as BannerTitle, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BadgeGroup, BadgeGroupCount, Banner, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, Chip, ChipRemove, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CounterBadge, CountryFlag, DataTable, DataTree, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerBackdrop, DrawerBar, DrawerClose, DrawerContent, DrawerCreateHandle, DrawerDescription, DrawerFooter, DrawerHeader, DrawerMenu, DrawerMenuCheckboxItem, DrawerMenuGroup, DrawerMenuGroupLabel, DrawerMenuItem, DrawerMenuRadioGroup, DrawerMenuRadioItem, DrawerMenuSeparator, DrawerMenuTrigger, DrawerPanel, DrawerPopup, DrawerPortal, DrawerPrimitive, DrawerSwipeArea, DrawerTitle, DrawerTrigger, DrawerViewport, DropdownMenu, DropdownMenuAddon, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, DropzoneActions, DropzoneContent, DropzoneDescription, DropzoneIcon, DropzoneTitle, DropzoneTrigger, DsI18nProvider, EmojiPicker, EmojiPickerCategories, EmojiPickerContent, EmojiPickerTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, FAB, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Filter, FilterClearAllButton, FilterGroup, Gauge, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Label, List, ListCol, ListRow, NotificationQueueProvider, NotificationSlot, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, ProgressIndicator, ProgressLabel, ProgressTrack, ProgressValue, RadioGroup, RadioGroupItem, SUPPORTED_LANGUAGES, ScrollArea, ScrollAreaPrimitive, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, Stepper, StepperContent, StepperCounter, StepperPanel, StepperProgress, Switch, Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Tree, TreeDragLine, TreeItem, TreeItemLabel, alertVariants, bannerVariants, buttonGroupVariants, buttonVariants, cn, counterBadgeVariants, detectInitialLanguage, fabVariants, registerI18nNamespace, selectTriggerVariants, spinnerVariants, syncDsLanguage, toast, toggleVariants, useAudioGauge, useComboboxAnchor, useDsTranslation, useNotification, useNotificationQueue, useSidebar, useStepper, useTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aircall/ds",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "sideEffects": [
@@ -17,7 +17,8 @@
17
17
  "src/fonts",
18
18
  "README.md",
19
19
  "AGENTS.consumer.md",
20
- "package.json"
20
+ "package.json",
21
+ "skills"
21
22
  ],
22
23
  "exports": {
23
24
  ".": {
@@ -33,6 +34,7 @@
33
34
  "@aircall/react-icons": "*",
34
35
  "@tanstack/react-table": "^8.0.0",
35
36
  "date-fns": "^4.0.0",
37
+ "i18next": ">=20.3.0 <24",
36
38
  "react": "^18.0.0 || ^19.0.0",
37
39
  "react-day-picker": "^9.0.0",
38
40
  "react-dom": "^18.0.0 || ^19.0.0"
@@ -80,6 +82,7 @@
80
82
  "@storybook/react-vite": "10.3.3",
81
83
  "@tailwindcss/cli": "4.1.18",
82
84
  "@tailwindcss/postcss": "4.1.18",
85
+ "@tanstack/intent": "0.1.1",
83
86
  "@tanstack/react-table": "8.20.6",
84
87
  "@turbo/gen": "2.4.2",
85
88
  "@types/node": "24",
@@ -89,6 +92,7 @@
89
92
  "@vitest/coverage-v8": "4.0.17",
90
93
  "chromatic": "13.3.5",
91
94
  "date-fns": "4.1.0",
95
+ "i18next": "23.11.5",
92
96
  "playwright": "1.57.0",
93
97
  "react": "19.2.3",
94
98
  "react-compiler-runtime": "1.0.0",
@@ -103,6 +107,14 @@
103
107
  "vitest": "4.0.17",
104
108
  "@aircall/hooks": "0.5.1"
105
109
  },
110
+ "keywords": [
111
+ "tanstack-intent"
112
+ ],
113
+ "repository": {
114
+ "type": "git",
115
+ "url": "git+https://gitlab.com/aircall/shared/hydra.git",
116
+ "directory": "packages/ds"
117
+ },
106
118
  "scripts": {
107
119
  "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
108
120
  "build:js": "tsdown --config ./tsdown.config.ts",
@@ -116,7 +128,8 @@
116
128
  "sb:build:deploy": "pnpm run registry:build && storybook build",
117
129
  "sb:test": "vitest --project=storybook",
118
130
  "sb:build:chromatic": "storybook build --test --stats-json",
119
- "chromatic": "chromatic --storybook-build-dir=./storybook-static"
131
+ "chromatic": "chromatic --storybook-build-dir=./storybook-static",
132
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
120
133
  },
121
134
  "types": "./dist/index.d.ts",
122
135
  "module": "./dist/index.js",