@mediquo/medicore 0.4.1 → 0.5.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 (82) hide show
  1. package/dist/components/advisor-contact/advisor-contact.js +1 -1
  2. package/dist/components/advisor-contact/advisor-contact.js.map +1 -1
  3. package/dist/components/bottom-bar/bottom-bar.js +1 -1
  4. package/dist/components/bottom-bar/bottom-bar.js.map +1 -1
  5. package/dist/components/brand-bubbles/brand-bubbles.d.ts +2 -2
  6. package/dist/components/brand-bubbles/brand-bubbles.js +0 -22
  7. package/dist/components/brand-bubbles/brand-bubbles.js.map +1 -1
  8. package/dist/components/breadcrumb/breadcrumb.js +1 -1
  9. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  10. package/dist/components/button/button.d.ts +2 -1
  11. package/dist/components/button/button.js +8 -4
  12. package/dist/components/button/button.js.map +1 -1
  13. package/dist/components/card/card.d.ts +2 -1
  14. package/dist/components/card/card.js +10 -3
  15. package/dist/components/card/card.js.map +1 -1
  16. package/dist/components/card-article/card-article.js +6 -2
  17. package/dist/components/card-article/card-article.js.map +1 -1
  18. package/dist/components/card-professional-mini/card-professional-mini.js +1 -1
  19. package/dist/components/card-professional-mini/card-professional-mini.js.map +1 -1
  20. package/dist/components/card-program/card-program.js +9 -3
  21. package/dist/components/card-program/card-program.js.map +1 -1
  22. package/dist/components/chat/chat-composer.js +1 -1
  23. package/dist/components/chat/chat-composer.js.map +1 -1
  24. package/dist/components/chat/chat-conversation-row.js +1 -1
  25. package/dist/components/chat/chat-conversation-row.js.map +1 -1
  26. package/dist/components/checkbox/checkbox.js +2 -1
  27. package/dist/components/checkbox/checkbox.js.map +1 -1
  28. package/dist/components/chip/chip.js +2 -2
  29. package/dist/components/chip/chip.js.map +1 -1
  30. package/dist/components/day-cell/day-cell.js +2 -1
  31. package/dist/components/day-cell/day-cell.js.map +1 -1
  32. package/dist/components/hover-arrow/hover-arrow.d.ts +4 -0
  33. package/dist/components/hover-arrow/hover-arrow.js +18 -0
  34. package/dist/components/hover-arrow/hover-arrow.js.map +1 -0
  35. package/dist/components/hover-arrow/index.d.ts +1 -0
  36. package/dist/components/input/control-styles.d.ts +2 -2
  37. package/dist/components/input/control-styles.js +2 -2
  38. package/dist/components/input/control-styles.js.map +1 -1
  39. package/dist/components/link/link.d.ts +2 -1
  40. package/dist/components/link/link.js +8 -5
  41. package/dist/components/link/link.js.map +1 -1
  42. package/dist/components/list-row/list-row.js +1 -1
  43. package/dist/components/list-row/list-row.js.map +1 -1
  44. package/dist/components/menu/menu.js +1 -1
  45. package/dist/components/menu/menu.js.map +1 -1
  46. package/dist/components/modal/modal.js +1 -1
  47. package/dist/components/modal/modal.js.map +1 -1
  48. package/dist/components/nav-item/nav-item.js +2 -2
  49. package/dist/components/nav-item/nav-item.js.map +1 -1
  50. package/dist/components/otp-input/otp-input.js +3 -2
  51. package/dist/components/otp-input/otp-input.js.map +1 -1
  52. package/dist/components/radio/radio.js +2 -1
  53. package/dist/components/radio/radio.js.map +1 -1
  54. package/dist/components/segmented-control/segmented-control.js +1 -1
  55. package/dist/components/segmented-control/segmented-control.js.map +1 -1
  56. package/dist/components/select/select.js +1 -1
  57. package/dist/components/select/select.js.map +1 -1
  58. package/dist/components/selection-card/selection-card.js +2 -1
  59. package/dist/components/selection-card/selection-card.js.map +1 -1
  60. package/dist/components/switch/switch.js +3 -2
  61. package/dist/components/switch/switch.js.map +1 -1
  62. package/dist/components/table/table.js +3 -3
  63. package/dist/components/table/table.js.map +1 -1
  64. package/dist/components/tabs/tabs.js +3 -3
  65. package/dist/components/tabs/tabs.js.map +1 -1
  66. package/dist/components/time-slot/time-slot.js +2 -1
  67. package/dist/components/time-slot/time-slot.js.map +1 -1
  68. package/dist/components/toast/toast.js +1 -1
  69. package/dist/components/toast/toast.js.map +1 -1
  70. package/dist/components/tooltip/tooltip.js +1 -1
  71. package/dist/components/tooltip/tooltip.js.map +1 -1
  72. package/dist/components/video/video-control-button.js +1 -1
  73. package/dist/components/video/video-control-button.js.map +1 -1
  74. package/dist/icons/create-icon.d.ts +1 -0
  75. package/dist/icons/create-icon.js +7 -1
  76. package/dist/icons/create-icon.js.map +1 -1
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.js +2 -0
  79. package/dist/index.js.map +1 -1
  80. package/dist/styles/tokens.css +5 -23
  81. package/dist/styles/utilities.css +121 -0
  82. package/package.json +1 -1
@@ -61,7 +61,7 @@ function AdvisorContact({
61
61
  className: cn(
62
62
  "relative flex min-w-0 items-center rounded-lg border px-3 py-2",
63
63
  hero ? "gap-4 border-border-inverse" : "gap-3 border-border-subtle bg-background",
64
- isLink && "transition-colors hover:bg-surface",
64
+ isLink && "interactive hover:bg-surface",
65
65
  className
66
66
  ),
67
67
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"advisor-contact.js","sources":["../../../src/components/advisor-contact/advisor-contact.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\nimport { Avatar, type AvatarSize } from \"../avatar\";\nimport { CardLink } from \"../card\";\n\nexport type AdvisorContactVariant = \"hero\" | \"bar\" | \"callout\";\n\nexport interface AdvisorContactProps\n extends Omit<ComponentProps<\"div\">, \"title\"> {\n /**\n * `hero` (default): on the home greeting (dark background) · `bar`: in the header of\n * the programme pages, the whole bar opens the chat (`href`) · `callout`: inside a\n * programme page, after the options. The callout stacks by itself (Figma\n * `Stacked`) when its column is narrower than 560px.\n */\n variant?: AdvisorContactVariant;\n /** Hero/Bar: \"Víctor Martínez · Tu asesor de salud\". Callout: \"¿No sabes cuál elegir?\". */\n title: ReactNode;\n /** \"Hola, Marta. Cuéntame en qué te ayudo.\" / \"¿Te ayudo a elegir?\". */\n message: ReactNode;\n /** The advisor's photo. */\n avatarSrc?: string;\n /**\n * Available right now: the green dot, named \"Disponible ahora\"\n * (`advisorAvailable` label). If not, leave it out and say in `message` when they\n * answer.\n */\n available?: boolean;\n /**\n * Hero: an `inverse-ghost` small `Button` \"Escribir\" with `MessageIcon`. Callout: a\n * secondary `Button` \"Escribir a Víctor\". It opens the chat with the advisor.\n */\n action?: ReactNode;\n /** Bar: the chat with the advisor. The whole bar is this link. */\n href?: string;\n /** Bar: router link, `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n}\n\nconst avatarSizes: Record<AdvisorContactVariant, AvatarSize> = {\n hero: 40,\n bar: 32,\n callout: 48,\n};\n\n/**\n * Access to the patient's health advisor: a real person from the team, not a\n * doctor. Presented as \"tu asesor de salud\", never \"asesor comercial\": they help to\n * choose, they don't sell, and they never give medical advice.\n */\nexport function AdvisorContact({\n variant = \"hero\",\n title,\n message,\n avatarSrc,\n available = false,\n action,\n href,\n render,\n className,\n ...props\n}: AdvisorContactProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n const avatar = available ? (\n <Avatar\n size={avatarSizes[variant]}\n src={avatarSrc}\n status=\"online\"\n statusLabel={labels.advisorAvailable}\n />\n ) : (\n <Avatar size={avatarSizes[variant]} src={avatarSrc} />\n );\n\n if (variant === \"callout\") {\n return (\n <div\n data-slot=\"advisor-contact\"\n data-variant=\"callout\"\n className={cn(\"@container rounded-xl bg-brand-subtle\", className)}\n {...props}\n >\n <div className=\"flex flex-col gap-4 px-6 py-4 @min-[560px]:flex-row @min-[560px]:items-center\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3 @min-[560px]:gap-4\">\n {avatar}\n <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <p className=\"text-label-strong text-text-primary\">{title}</p>\n <p className=\"text-body-small text-text-primary\">{message}</p>\n </div>\n </div>\n {action && (\n <div className=\"flex shrink-0 *:flex-1 @min-[560px]:*:flex-none\">\n {action}\n </div>\n )}\n </div>\n </div>\n );\n }\n\n const hero = variant === \"hero\";\n const isLink = !hero && Boolean(href || render);\n\n return (\n <div\n data-slot=\"advisor-contact\"\n data-variant={variant}\n className={cn(\n \"relative flex min-w-0 items-center rounded-lg border px-3 py-2\",\n hero\n ? \"gap-4 border-border-inverse\"\n : \"gap-3 border-border-subtle bg-background\",\n isLink && \"transition-colors hover:bg-surface\",\n className,\n )}\n {...props}\n >\n {avatar}\n <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <p\n className={\n hero\n ? \"text-label-small text-text-inverse-secondary\"\n : \"text-label-strong text-text-primary\"\n }\n >\n {isLink ? (\n <CardLink href={href} render={render} className=\"after:rounded-lg\">\n {title}\n </CardLink>\n ) : (\n title\n )}\n </p>\n <p\n className={\n hero\n ? \"text-label-strong text-text-inverse\"\n : \"text-body-small text-text-secondary\"\n }\n >\n {message}\n </p>\n </div>\n {action && <div className=\"relative z-10 flex shrink-0\">{action}</div>}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AA0CA,MAAM,cAAyD;AAAA,EAC7D,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AACX;AAOO,SAAS,eAAe;AAAA,EAC7B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,QAAM,SAAS,kBAAA;AACf,QAAM,SAAS,YACb;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAM,YAAY,OAAO;AAAA,MACzB,KAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa,OAAO;AAAA,IAAA;AAAA,EAAA,wBAGrB,QAAA,EAAO,MAAM,YAAY,OAAO,GAAG,KAAK,WAAW;AAGtD,MAAI,YAAY,WAAW;AACzB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,aAAU;AAAA,QACV,gBAAa;AAAA,QACb,WAAW,GAAG,yCAAyC,SAAS;AAAA,QAC/D,GAAG;AAAA,QAEJ,UAAA,qBAAC,OAAA,EAAI,WAAU,iFACb,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,6DACZ,UAAA;AAAA,YAAA;AAAA,YACD,qBAAC,OAAA,EAAI,WAAU,wCACb,UAAA;AAAA,cAAA,oBAAC,KAAA,EAAE,WAAU,uCAAuC,UAAA,OAAM;AAAA,cAC1D,oBAAC,KAAA,EAAE,WAAU,qCAAqC,UAAA,QAAA,CAAQ;AAAA,YAAA,EAAA,CAC5D;AAAA,UAAA,GACF;AAAA,UACC,UACC,oBAAC,OAAA,EAAI,WAAU,mDACZ,UAAA,OAAA,CACH;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AAEA,QAAM,OAAO,YAAY;AACzB,QAAM,SAAS,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AAE9C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,WAAW;AAAA,QACT;AAAA,QACA,OACI,gCACA;AAAA,QACJ,UAAU;AAAA,QACV;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACD,qBAAC,OAAA,EAAI,WAAU,wCACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WACE,OACI,iDACA;AAAA,cAGL,UAAA,6BACE,UAAA,EAAS,MAAY,QAAgB,WAAU,oBAC7C,iBACH,IAEA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGJ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WACE,OACI,wCACA;AAAA,cAGL,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH,GACF;AAAA,QACC,UAAU,oBAAC,OAAA,EAAI,WAAU,+BAA+B,UAAA,OAAA,CAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGtE;"}
1
+ {"version":3,"file":"advisor-contact.js","sources":["../../../src/components/advisor-contact/advisor-contact.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\nimport { Avatar, type AvatarSize } from \"../avatar\";\nimport { CardLink } from \"../card\";\n\nexport type AdvisorContactVariant = \"hero\" | \"bar\" | \"callout\";\n\nexport interface AdvisorContactProps\n extends Omit<ComponentProps<\"div\">, \"title\"> {\n /**\n * `hero` (default): on the home greeting (dark background) · `bar`: in the header of\n * the programme pages, the whole bar opens the chat (`href`) · `callout`: inside a\n * programme page, after the options. The callout stacks by itself (Figma\n * `Stacked`) when its column is narrower than 560px.\n */\n variant?: AdvisorContactVariant;\n /** Hero/Bar: \"Víctor Martínez · Tu asesor de salud\". Callout: \"¿No sabes cuál elegir?\". */\n title: ReactNode;\n /** \"Hola, Marta. Cuéntame en qué te ayudo.\" / \"¿Te ayudo a elegir?\". */\n message: ReactNode;\n /** The advisor's photo. */\n avatarSrc?: string;\n /**\n * Available right now: the green dot, named \"Disponible ahora\"\n * (`advisorAvailable` label). If not, leave it out and say in `message` when they\n * answer.\n */\n available?: boolean;\n /**\n * Hero: an `inverse-ghost` small `Button` \"Escribir\" with `MessageIcon`. Callout: a\n * secondary `Button` \"Escribir a Víctor\". It opens the chat with the advisor.\n */\n action?: ReactNode;\n /** Bar: the chat with the advisor. The whole bar is this link. */\n href?: string;\n /** Bar: router link, `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n}\n\nconst avatarSizes: Record<AdvisorContactVariant, AvatarSize> = {\n hero: 40,\n bar: 32,\n callout: 48,\n};\n\n/**\n * Access to the patient's health advisor: a real person from the team, not a\n * doctor. Presented as \"tu asesor de salud\", never \"asesor comercial\": they help to\n * choose, they don't sell, and they never give medical advice.\n */\nexport function AdvisorContact({\n variant = \"hero\",\n title,\n message,\n avatarSrc,\n available = false,\n action,\n href,\n render,\n className,\n ...props\n}: AdvisorContactProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n const avatar = available ? (\n <Avatar\n size={avatarSizes[variant]}\n src={avatarSrc}\n status=\"online\"\n statusLabel={labels.advisorAvailable}\n />\n ) : (\n <Avatar size={avatarSizes[variant]} src={avatarSrc} />\n );\n\n if (variant === \"callout\") {\n return (\n <div\n data-slot=\"advisor-contact\"\n data-variant=\"callout\"\n className={cn(\"@container rounded-xl bg-brand-subtle\", className)}\n {...props}\n >\n <div className=\"flex flex-col gap-4 px-6 py-4 @min-[560px]:flex-row @min-[560px]:items-center\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3 @min-[560px]:gap-4\">\n {avatar}\n <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <p className=\"text-label-strong text-text-primary\">{title}</p>\n <p className=\"text-body-small text-text-primary\">{message}</p>\n </div>\n </div>\n {action && (\n <div className=\"flex shrink-0 *:flex-1 @min-[560px]:*:flex-none\">\n {action}\n </div>\n )}\n </div>\n </div>\n );\n }\n\n const hero = variant === \"hero\";\n const isLink = !hero && Boolean(href || render);\n\n return (\n <div\n data-slot=\"advisor-contact\"\n data-variant={variant}\n className={cn(\n \"relative flex min-w-0 items-center rounded-lg border px-3 py-2\",\n hero\n ? \"gap-4 border-border-inverse\"\n : \"gap-3 border-border-subtle bg-background\",\n isLink && \"interactive hover:bg-surface\",\n className,\n )}\n {...props}\n >\n {avatar}\n <div className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <p\n className={\n hero\n ? \"text-label-small text-text-inverse-secondary\"\n : \"text-label-strong text-text-primary\"\n }\n >\n {isLink ? (\n <CardLink href={href} render={render} className=\"after:rounded-lg\">\n {title}\n </CardLink>\n ) : (\n title\n )}\n </p>\n <p\n className={\n hero\n ? \"text-label-strong text-text-inverse\"\n : \"text-body-small text-text-secondary\"\n }\n >\n {message}\n </p>\n </div>\n {action && <div className=\"relative z-10 flex shrink-0\">{action}</div>}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AA0CA,MAAM,cAAyD;AAAA,EAC7D,MAAM;AAAA,EACN,KAAK;AAAA,EACL,SAAS;AACX;AAOO,SAAS,eAAe;AAAA,EAC7B,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,QAAM,SAAS,kBAAA;AACf,QAAM,SAAS,YACb;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAM,YAAY,OAAO;AAAA,MACzB,KAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa,OAAO;AAAA,IAAA;AAAA,EAAA,wBAGrB,QAAA,EAAO,MAAM,YAAY,OAAO,GAAG,KAAK,WAAW;AAGtD,MAAI,YAAY,WAAW;AACzB,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,aAAU;AAAA,QACV,gBAAa;AAAA,QACb,WAAW,GAAG,yCAAyC,SAAS;AAAA,QAC/D,GAAG;AAAA,QAEJ,UAAA,qBAAC,OAAA,EAAI,WAAU,iFACb,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,6DACZ,UAAA;AAAA,YAAA;AAAA,YACD,qBAAC,OAAA,EAAI,WAAU,wCACb,UAAA;AAAA,cAAA,oBAAC,KAAA,EAAE,WAAU,uCAAuC,UAAA,OAAM;AAAA,cAC1D,oBAAC,KAAA,EAAE,WAAU,qCAAqC,UAAA,QAAA,CAAQ;AAAA,YAAA,EAAA,CAC5D;AAAA,UAAA,GACF;AAAA,UACC,UACC,oBAAC,OAAA,EAAI,WAAU,mDACZ,UAAA,OAAA,CACH;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AAEA,QAAM,OAAO,YAAY;AACzB,QAAM,SAAS,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AAE9C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,WAAW;AAAA,QACT;AAAA,QACA,OACI,gCACA;AAAA,QACJ,UAAU;AAAA,QACV;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA;AAAA,QACD,qBAAC,OAAA,EAAI,WAAU,wCACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WACE,OACI,iDACA;AAAA,cAGL,UAAA,6BACE,UAAA,EAAS,MAAY,QAAgB,WAAU,oBAC7C,iBACH,IAEA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGJ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WACE,OACI,wCACA;AAAA,cAGL,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QACH,GACF;AAAA,QACC,UAAU,oBAAC,OAAA,EAAI,WAAU,+BAA+B,UAAA,OAAA,CAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGtE;"}
@@ -27,7 +27,7 @@ function BottomBar({
27
27
  }
28
28
  const bottomBarItemVariants = cva([
29
29
  "group/tab relative flex min-w-0 flex-1 cursor-pointer select-none flex-col items-center justify-center gap-1 rounded-md",
30
- "text-label-small text-text-secondary no-underline transition-colors",
30
+ "text-label-small text-text-secondary no-underline interactive",
31
31
  "[&_svg]:size-5.5 [&_svg]:shrink-0",
32
32
  "not-aria-[current=page]:hover:text-text-primary",
33
33
  "aria-[current=page]:text-text-brand",
@@ -1 +1 @@
1
- {"version":3,"file":"bottom-bar.js","sources":["../../../src/components/bottom-bar/bottom-bar.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cva } from \"class-variance-authority\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BottomBarProps extends ComponentProps<\"nav\"> {}\n\n/**\n * Mobile tab bar: a `<nav>` named \"Navegación principal\" with a list of links, the\n * current one with `aria-current=\"page\"`. Tabs share the width equally (five at 75px\n * on a 375 phone) and it adds the iPhone's `safe-area-inset-bottom` under its 77px.\n *\n * - Up to five tabs, the main sections. Everything else must stay reachable from the\n * menu in `MobileHeader` (see `AppShell`).\n * - A tab may use the short form of the section's name (\"Documentos\" for \"Mis\n * documentos\"), never a different name. If a label doesn't fit, shorten the word;\n * don't lower the 12px.\n * - `AppShell` keeps it at the bottom of the screen below the desktop breakpoint.\n */\nexport function BottomBar({\n \"aria-label\": ariaLabel,\n className,\n children,\n ...props\n}: BottomBarProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n return (\n <nav\n data-slot=\"bottom-bar\"\n aria-label={ariaLabel ?? labels.mainNavigation}\n className={cn(\n \"border-border border-t bg-surface pb-[env(safe-area-inset-bottom)]\",\n className,\n )}\n {...props}\n >\n <ul className=\"flex h-19.25\">{children}</ul>\n </nav>\n );\n}\n\nexport const bottomBarItemVariants = cva([\n \"group/tab relative flex min-w-0 flex-1 cursor-pointer select-none flex-col items-center justify-center gap-1 rounded-md\",\n \"text-label-small text-text-secondary no-underline transition-colors\",\n \"[&_svg]:size-5.5 [&_svg]:shrink-0\",\n \"not-aria-[current=page]:hover:text-text-primary\",\n \"aria-[current=page]:text-text-brand\",\n // Inside the tab: the tabs touch each other, there is no room outside.\n \"focus-ring focus-visible:-outline-offset-2\",\n]);\n\nexport interface BottomBarItemProps\n extends Omit<useRender.ComponentProps<\"a\">, \"className\" | \"children\"> {\n /** A MediCore icon, drawn at 22px. */\n icon: ReactNode;\n /** 12px label (Label/Small). Always visible: an icon-only tab bar is a guessing game. */\n children: ReactNode;\n /**\n * The tab of the current screen: `aria-current=\"page\"`, brand colour and a 3px bar\n * on top (the non-colour cue). Leave it out if the router link sets\n * `aria-current=\"page\"` itself.\n */\n active?: boolean;\n /**\n * The central action of the product (\"Pedir cita\"): the icon sits in a\n * `brand-subtle` circle. At most one per bar.\n */\n featured?: boolean;\n className?: string;\n}\n\n/**\n * One tab (Figma `Nav/TabItem`). Renders an `<a>` inside an `<li>`; pass the router's\n * link with `render={<Link to=\"/agenda\" />}`.\n */\nexport function BottomBarItem({\n icon,\n children,\n active = false,\n featured = false,\n className,\n render,\n ...props\n}: BottomBarItemProps): React.JSX.Element {\n const ownProps: useRender.ElementProps<\"a\"> & { \"data-slot\": string } = {\n \"data-slot\": \"bottom-bar-link\",\n className: cn(bottomBarItemVariants(), className),\n \"aria-current\": active ? \"page\" : undefined,\n children: (\n <>\n <span\n aria-hidden\n data-slot=\"bottom-bar-indicator\"\n className=\"absolute inset-x-0 top-0 hidden h-0.75 rounded-b-xs bg-text-brand group-aria-[current=page]/tab:block\"\n />\n {featured ? (\n <span className=\"flex size-9.5 items-center justify-center rounded-full bg-brand-subtle\">\n {icon}\n </span>\n ) : (\n icon\n )}\n <span className=\"max-w-full truncate\">{children}</span>\n </>\n ),\n };\n\n const element = useRender({\n defaultTagName: \"a\",\n render,\n state: { active, featured },\n props: mergeProps<\"a\">(ownProps, props),\n });\n\n return (\n <li data-slot=\"bottom-bar-item\" className=\"flex min-w-0 flex-1\">\n {element}\n </li>\n );\n}\n"],"names":[],"mappings":";;;;;;AAsBO,SAAS,UAAU;AAAA,EACxB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,QAAM,SAAS,kBAAA;AAEf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,aAAa,OAAO;AAAA,MAChC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA,oBAAC,MAAA,EAAG,WAAU,gBAAgB,SAAA,CAAS;AAAA,IAAA;AAAA,EAAA;AAG7C;AAEO,MAAM,wBAAwB,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF,CAAC;AA0BM,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA0C;AACxC,QAAM,WAAkE;AAAA,IACtE,aAAa;AAAA,IACb,WAAW,GAAG,sBAAA,GAAyB,SAAS;AAAA,IAChD,gBAAgB,SAAS,SAAS;AAAA,IAClC,UACE,qBAAA,UAAA,EACE,UAAA;AAAA,MAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAW;AAAA,UACX,aAAU;AAAA,UACV,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,MAEX,WACC,oBAAC,QAAA,EAAK,WAAU,0EACb,gBACH,IAEA;AAAA,MAEF,oBAAC,QAAA,EAAK,WAAU,uBAAuB,SAAA,CAAS;AAAA,IAAA,EAAA,CAClD;AAAA,EAAA;AAIJ,QAAM,UAAU,UAAU;AAAA,IACxB,gBAAgB;AAAA,IAChB;AAAA,IACA,OAAO,EAAE,QAAQ,SAAA;AAAA,IACjB,OAAO,WAAgB,UAAU,KAAK;AAAA,EAAA,CACvC;AAED,6BACG,MAAA,EAAG,aAAU,mBAAkB,WAAU,uBACvC,UAAA,SACH;AAEJ;"}
1
+ {"version":3,"file":"bottom-bar.js","sources":["../../../src/components/bottom-bar/bottom-bar.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cva } from \"class-variance-authority\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BottomBarProps extends ComponentProps<\"nav\"> {}\n\n/**\n * Mobile tab bar: a `<nav>` named \"Navegación principal\" with a list of links, the\n * current one with `aria-current=\"page\"`. Tabs share the width equally (five at 75px\n * on a 375 phone) and it adds the iPhone's `safe-area-inset-bottom` under its 77px.\n *\n * - Up to five tabs, the main sections. Everything else must stay reachable from the\n * menu in `MobileHeader` (see `AppShell`).\n * - A tab may use the short form of the section's name (\"Documentos\" for \"Mis\n * documentos\"), never a different name. If a label doesn't fit, shorten the word;\n * don't lower the 12px.\n * - `AppShell` keeps it at the bottom of the screen below the desktop breakpoint.\n */\nexport function BottomBar({\n \"aria-label\": ariaLabel,\n className,\n children,\n ...props\n}: BottomBarProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n return (\n <nav\n data-slot=\"bottom-bar\"\n aria-label={ariaLabel ?? labels.mainNavigation}\n className={cn(\n \"border-border border-t bg-surface pb-[env(safe-area-inset-bottom)]\",\n className,\n )}\n {...props}\n >\n <ul className=\"flex h-19.25\">{children}</ul>\n </nav>\n );\n}\n\nexport const bottomBarItemVariants = cva([\n \"group/tab relative flex min-w-0 flex-1 cursor-pointer select-none flex-col items-center justify-center gap-1 rounded-md\",\n \"text-label-small text-text-secondary no-underline interactive\",\n \"[&_svg]:size-5.5 [&_svg]:shrink-0\",\n \"not-aria-[current=page]:hover:text-text-primary\",\n \"aria-[current=page]:text-text-brand\",\n // Inside the tab: the tabs touch each other, there is no room outside.\n \"focus-ring focus-visible:-outline-offset-2\",\n]);\n\nexport interface BottomBarItemProps\n extends Omit<useRender.ComponentProps<\"a\">, \"className\" | \"children\"> {\n /** A MediCore icon, drawn at 22px. */\n icon: ReactNode;\n /** 12px label (Label/Small). Always visible: an icon-only tab bar is a guessing game. */\n children: ReactNode;\n /**\n * The tab of the current screen: `aria-current=\"page\"`, brand colour and a 3px bar\n * on top (the non-colour cue). Leave it out if the router link sets\n * `aria-current=\"page\"` itself.\n */\n active?: boolean;\n /**\n * The central action of the product (\"Pedir cita\"): the icon sits in a\n * `brand-subtle` circle. At most one per bar.\n */\n featured?: boolean;\n className?: string;\n}\n\n/**\n * One tab (Figma `Nav/TabItem`). Renders an `<a>` inside an `<li>`; pass the router's\n * link with `render={<Link to=\"/agenda\" />}`.\n */\nexport function BottomBarItem({\n icon,\n children,\n active = false,\n featured = false,\n className,\n render,\n ...props\n}: BottomBarItemProps): React.JSX.Element {\n const ownProps: useRender.ElementProps<\"a\"> & { \"data-slot\": string } = {\n \"data-slot\": \"bottom-bar-link\",\n className: cn(bottomBarItemVariants(), className),\n \"aria-current\": active ? \"page\" : undefined,\n children: (\n <>\n <span\n aria-hidden\n data-slot=\"bottom-bar-indicator\"\n className=\"absolute inset-x-0 top-0 hidden h-0.75 rounded-b-xs bg-text-brand group-aria-[current=page]/tab:block\"\n />\n {featured ? (\n <span className=\"flex size-9.5 items-center justify-center rounded-full bg-brand-subtle\">\n {icon}\n </span>\n ) : (\n icon\n )}\n <span className=\"max-w-full truncate\">{children}</span>\n </>\n ),\n };\n\n const element = useRender({\n defaultTagName: \"a\",\n render,\n state: { active, featured },\n props: mergeProps<\"a\">(ownProps, props),\n });\n\n return (\n <li data-slot=\"bottom-bar-item\" className=\"flex min-w-0 flex-1\">\n {element}\n </li>\n );\n}\n"],"names":[],"mappings":";;;;;;AAsBO,SAAS,UAAU;AAAA,EACxB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,QAAM,SAAS,kBAAA;AAEf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,aAAa,OAAO;AAAA,MAChC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA,oBAAC,MAAA,EAAG,WAAU,gBAAgB,SAAA,CAAS;AAAA,IAAA;AAAA,EAAA;AAG7C;AAEO,MAAM,wBAAwB,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF,CAAC;AA0BM,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA0C;AACxC,QAAM,WAAkE;AAAA,IACtE,aAAa;AAAA,IACb,WAAW,GAAG,sBAAA,GAAyB,SAAS;AAAA,IAChD,gBAAgB,SAAS,SAAS;AAAA,IAClC,UACE,qBAAA,UAAA,EACE,UAAA;AAAA,MAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAW;AAAA,UACX,aAAU;AAAA,UACV,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,MAEX,WACC,oBAAC,QAAA,EAAK,WAAU,0EACb,gBACH,IAEA;AAAA,MAEF,oBAAC,QAAA,EAAK,WAAU,uBAAuB,SAAA,CAAS;AAAA,IAAA,EAAA,CAClD;AAAA,EAAA;AAIJ,QAAM,UAAU,UAAU;AAAA,IACxB,gBAAgB;AAAA,IAChB;AAAA,IACA,OAAO,EAAE,QAAQ,SAAA;AAAA,IACjB,OAAO,WAAgB,UAAU,KAAK;AAAA,EAAA,CACvC;AAED,6BACG,MAAA,EAAG,aAAU,mBAAkB,WAAU,uBACvC,UAAA,SACH;AAEJ;"}
@@ -2,8 +2,8 @@ import { type ComponentProps } from "react";
2
2
  export interface BrandBubblesProps extends Omit<ComponentProps<"svg">, "children"> {
3
3
  }
4
4
  /**
5
- * mediQuo's brand backdrop on a dark brand surface: translucent bubbles that float and
6
- * rise, breathing glows, a twinkling constellation and the cross. A seamless loop that
5
+ * mediQuo's brand backdrop on a dark brand surface: translucent bubbles that float on a
6
+ * wide path, breathing glows, a twinkling constellation and the cross. A seamless loop that
7
7
  * reads like a short video, in the same language as the portal's home hero, for the
8
8
  * `AuthPanel` and any other full-bleed brand surface.
9
9
  *
@@ -2,21 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useId } from "react";
3
3
  import { cn } from "../../lib/cn.js";
4
4
  const float = "motion-safe:animate-float";
5
- const rise = "motion-safe:animate-rise";
6
5
  const scaled = "origin-center [transform-box:fill-box]";
7
6
  const breathe = cn("motion-safe:animate-breathe", scaled);
8
7
  const twinkle = cn("motion-safe:animate-twinkle", scaled);
9
- const RISING_BUBBLES = [
10
- { cx: 70, r: 10, timing: "[animation-duration:15s]" },
11
- { cx: 150, r: 22, timing: "[animation-duration:19s] [animation-delay:-11s]" },
12
- { cx: 235, r: 7, timing: "[animation-duration:13s] [animation-delay:-4s]" },
13
- { cx: 300, r: 16, timing: "[animation-duration:17s] [animation-delay:-8s]" },
14
- { cx: 380, r: 9, timing: "[animation-duration:14s] [animation-delay:-2s]" },
15
- { cx: 445, r: 26, timing: "[animation-duration:21s] [animation-delay:-15s]" },
16
- { cx: 510, r: 12, timing: "[animation-duration:16s] [animation-delay:-6s]" },
17
- { cx: 110, r: 6, timing: "[animation-duration:12s] [animation-delay:-9s]" },
18
- { cx: 345, r: 5, timing: "[animation-duration:11s] [animation-delay:-5s]" }
19
- ];
20
8
  const CONSTELLATION = [
21
9
  { cx: 120, cy: 330, timing: "[animation-delay:0s]" },
22
10
  { cx: 300, cy: 520, timing: "[animation-delay:-0.8s]" },
@@ -116,16 +104,6 @@ function BrandBubbles({
116
104
  }
117
105
  )
118
106
  ] }),
119
- /* @__PURE__ */ jsx("g", { "data-slot": "brand-bubbles-rising", className: "fill-text-inverse/15", children: RISING_BUBBLES.map((bubble) => /* @__PURE__ */ jsx(
120
- "circle",
121
- {
122
- cx: bubble.cx,
123
- cy: "1080",
124
- r: bubble.r,
125
- className: cn(rise, bubble.timing)
126
- },
127
- bubble.cx
128
- )) }),
129
107
  /* @__PURE__ */ jsxs(
130
108
  "g",
131
109
  {
@@ -1 +1 @@
1
- {"version":3,"file":"brand-bubbles.js","sources":["../../../src/components/brand-bubbles/brand-bubbles.tsx"],"sourcesContent":["import { type ComponentProps, useId } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\n\nexport interface BrandBubblesProps\n extends Omit<ComponentProps<\"svg\">, \"children\"> {}\n\nconst float = \"motion-safe:animate-float\";\nconst rise = \"motion-safe:animate-rise\";\nconst scaled = \"origin-center [transform-box:fill-box]\";\nconst breathe = cn(\"motion-safe:animate-breathe\", scaled);\nconst twinkle = cn(\"motion-safe:animate-twinkle\", scaled);\n\nconst RISING_BUBBLES = [\n { cx: 70, r: 10, timing: \"[animation-duration:15s]\" },\n { cx: 150, r: 22, timing: \"[animation-duration:19s] [animation-delay:-11s]\" },\n { cx: 235, r: 7, timing: \"[animation-duration:13s] [animation-delay:-4s]\" },\n { cx: 300, r: 16, timing: \"[animation-duration:17s] [animation-delay:-8s]\" },\n { cx: 380, r: 9, timing: \"[animation-duration:14s] [animation-delay:-2s]\" },\n { cx: 445, r: 26, timing: \"[animation-duration:21s] [animation-delay:-15s]\" },\n { cx: 510, r: 12, timing: \"[animation-duration:16s] [animation-delay:-6s]\" },\n { cx: 110, r: 6, timing: \"[animation-duration:12s] [animation-delay:-9s]\" },\n { cx: 345, r: 5, timing: \"[animation-duration:11s] [animation-delay:-5s]\" },\n] as const;\n\nconst CONSTELLATION = [\n { cx: 120, cy: 330, timing: \"[animation-delay:0s]\" },\n { cx: 300, cy: 520, timing: \"[animation-delay:-0.8s]\" },\n { cx: 380, cy: 420, timing: \"[animation-delay:-1.6s]\" },\n { cx: 180, cy: 700, timing: \"[animation-delay:-2.4s]\" },\n] as const;\n\n/**\n * mediQuo's brand backdrop on a dark brand surface: translucent bubbles that float and\n * rise, breathing glows, a twinkling constellation and the cross. A seamless loop that\n * reads like a short video, in the same language as the portal's home hero, for the\n * `AuthPanel` and any other full-bleed brand surface.\n *\n * - Decorative: `aria-hidden`, no pointer events, never carries meaning.\n * - Fills its parent (`absolute inset-0`, `slice`), so the parent is `relative`\n * and clips overflow.\n * - Coloured with tokens (`text-inverse`, `brand`), so it follows a clinic's brand.\n * - Motion only under `prefers-reduced-motion: no-preference`; otherwise it is a\n * still composition. Transforms and opacity only, with gradients instead of blur\n * filters, so it stays smooth on large panels.\n */\nexport function BrandBubbles({\n className,\n ...props\n}: BrandBubblesProps): React.JSX.Element {\n const glowId = useId();\n\n return (\n <svg\n viewBox=\"0 0 560 1024\"\n preserveAspectRatio=\"xMidYMid slice\"\n aria-hidden=\"true\"\n focusable=\"false\"\n data-slot=\"brand-bubbles\"\n className={cn(\n \"pointer-events-none absolute inset-0 size-full select-none\",\n className,\n )}\n {...props}\n >\n <defs>\n <radialGradient id={glowId}>\n <stop\n offset=\"0%\"\n className=\"[stop-color:var(--color-brand)] [stop-opacity:0.6]\"\n />\n <stop\n offset=\"100%\"\n className=\"[stop-color:var(--color-brand)] [stop-opacity:0]\"\n />\n </radialGradient>\n </defs>\n\n <circle\n cx=\"440\"\n cy=\"180\"\n r=\"320\"\n fill={`url(#${glowId})`}\n className={cn(breathe, \"[animation-duration:11s]\")}\n />\n <circle\n cx=\"90\"\n cy=\"860\"\n r=\"300\"\n fill={`url(#${glowId})`}\n className={cn(\n breathe,\n \"[animation-duration:13s] [animation-delay:-5s]\",\n )}\n />\n\n <g className=\"fill-text-inverse/5\">\n <circle\n cx=\"430\"\n cy=\"150\"\n r=\"92\"\n className={cn(float, \"[animation-duration:12s]\")}\n />\n <circle\n cx=\"470\"\n cy=\"760\"\n r=\"140\"\n className={cn(\n float,\n \"[animation-duration:16s] [animation-delay:-6s]\",\n )}\n />\n <circle\n cx=\"120\"\n cy=\"330\"\n r=\"62\"\n className={cn(\n float,\n \"[animation-duration:10s] [animation-delay:-3s]\",\n )}\n />\n </g>\n\n <g data-slot=\"brand-bubbles-rising\" className=\"fill-text-inverse/15\">\n {RISING_BUBBLES.map((bubble) => (\n <circle\n key={bubble.cx}\n cx={bubble.cx}\n cy=\"1080\"\n r={bubble.r}\n className={cn(rise, bubble.timing)}\n />\n ))}\n </g>\n\n <g\n className={cn(float, \"[animation-duration:18s] [animation-delay:-4s]\")}\n >\n <g className=\"stroke-text-inverse opacity-15\" strokeWidth=\"1\">\n <path d=\"M120 330 L300 520\" />\n <path d=\"M300 520 L380 420\" />\n <path d=\"M300 520 L180 700\" />\n </g>\n <g className=\"fill-text-inverse/40\">\n {CONSTELLATION.map((dot) => (\n <circle\n key={`${dot.cx}-${dot.cy}`}\n cx={dot.cx}\n cy={dot.cy}\n r=\"5\"\n className={cn(twinkle, dot.timing)}\n />\n ))}\n </g>\n <g className=\"fill-text-inverse/25\">\n <rect x=\"412\" y=\"258\" width=\"36\" height=\"10\" rx=\"5\" />\n <rect x=\"425\" y=\"245\" width=\"10\" height=\"36\" rx=\"5\" />\n </g>\n </g>\n </svg>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brand-bubbles.js","sources":["../../../src/components/brand-bubbles/brand-bubbles.tsx"],"sourcesContent":["import { type ComponentProps, useId } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\n\nexport interface BrandBubblesProps\n extends Omit<ComponentProps<\"svg\">, \"children\"> {}\n\nconst float = \"motion-safe:animate-float\";\nconst scaled = \"origin-center [transform-box:fill-box]\";\nconst breathe = cn(\"motion-safe:animate-breathe\", scaled);\nconst twinkle = cn(\"motion-safe:animate-twinkle\", scaled);\n\nconst CONSTELLATION = [\n { cx: 120, cy: 330, timing: \"[animation-delay:0s]\" },\n { cx: 300, cy: 520, timing: \"[animation-delay:-0.8s]\" },\n { cx: 380, cy: 420, timing: \"[animation-delay:-1.6s]\" },\n { cx: 180, cy: 700, timing: \"[animation-delay:-2.4s]\" },\n] as const;\n\n/**\n * mediQuo's brand backdrop on a dark brand surface: translucent bubbles that float on a\n * wide path, breathing glows, a twinkling constellation and the cross. A seamless loop that\n * reads like a short video, in the same language as the portal's home hero, for the\n * `AuthPanel` and any other full-bleed brand surface.\n *\n * - Decorative: `aria-hidden`, no pointer events, never carries meaning.\n * - Fills its parent (`absolute inset-0`, `slice`), so the parent is `relative`\n * and clips overflow.\n * - Coloured with tokens (`text-inverse`, `brand`), so it follows a clinic's brand.\n * - Motion only under `prefers-reduced-motion: no-preference`; otherwise it is a\n * still composition. Transforms and opacity only, with gradients instead of blur\n * filters, so it stays smooth on large panels.\n */\nexport function BrandBubbles({\n className,\n ...props\n}: BrandBubblesProps): React.JSX.Element {\n const glowId = useId();\n\n return (\n <svg\n viewBox=\"0 0 560 1024\"\n preserveAspectRatio=\"xMidYMid slice\"\n aria-hidden=\"true\"\n focusable=\"false\"\n data-slot=\"brand-bubbles\"\n className={cn(\n \"pointer-events-none absolute inset-0 size-full select-none\",\n className,\n )}\n {...props}\n >\n <defs>\n <radialGradient id={glowId}>\n <stop\n offset=\"0%\"\n className=\"[stop-color:var(--color-brand)] [stop-opacity:0.6]\"\n />\n <stop\n offset=\"100%\"\n className=\"[stop-color:var(--color-brand)] [stop-opacity:0]\"\n />\n </radialGradient>\n </defs>\n\n <circle\n cx=\"440\"\n cy=\"180\"\n r=\"320\"\n fill={`url(#${glowId})`}\n className={cn(breathe, \"[animation-duration:11s]\")}\n />\n <circle\n cx=\"90\"\n cy=\"860\"\n r=\"300\"\n fill={`url(#${glowId})`}\n className={cn(\n breathe,\n \"[animation-duration:13s] [animation-delay:-5s]\",\n )}\n />\n\n <g className=\"fill-text-inverse/5\">\n <circle\n cx=\"430\"\n cy=\"150\"\n r=\"92\"\n className={cn(float, \"[animation-duration:12s]\")}\n />\n <circle\n cx=\"470\"\n cy=\"760\"\n r=\"140\"\n className={cn(\n float,\n \"[animation-duration:16s] [animation-delay:-6s]\",\n )}\n />\n <circle\n cx=\"120\"\n cy=\"330\"\n r=\"62\"\n className={cn(\n float,\n \"[animation-duration:10s] [animation-delay:-3s]\",\n )}\n />\n </g>\n\n <g\n className={cn(float, \"[animation-duration:18s] [animation-delay:-4s]\")}\n >\n <g className=\"stroke-text-inverse opacity-15\" strokeWidth=\"1\">\n <path d=\"M120 330 L300 520\" />\n <path d=\"M300 520 L380 420\" />\n <path d=\"M300 520 L180 700\" />\n </g>\n <g className=\"fill-text-inverse/40\">\n {CONSTELLATION.map((dot) => (\n <circle\n key={`${dot.cx}-${dot.cy}`}\n cx={dot.cx}\n cy={dot.cy}\n r=\"5\"\n className={cn(twinkle, dot.timing)}\n />\n ))}\n </g>\n <g className=\"fill-text-inverse/25\">\n <rect x=\"412\" y=\"258\" width=\"36\" height=\"10\" rx=\"5\" />\n <rect x=\"425\" y=\"245\" width=\"10\" height=\"36\" rx=\"5\" />\n </g>\n </g>\n </svg>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -46,7 +46,7 @@ function BreadcrumbItem({
46
46
  props: {
47
47
  "data-slot": "breadcrumb-link",
48
48
  className: cn(
49
- "focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary transition-colors hover:text-text-brand",
49
+ "focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary interactive hover:text-text-brand",
50
50
  className
51
51
  ),
52
52
  children,
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.js","sources":["../../../src/components/breadcrumb/breadcrumb.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ChevronLeftIcon, ChevronRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BreadcrumbProps extends ComponentProps<\"nav\"> {\n /** `BreadcrumbItem`s for the levels above, then one `BreadcrumbPage` for the current one. */\n children: ReactNode;\n}\n\n/**\n * Breadcrumb for pages two or three levels deep (a programme inside \"Programas\n * especializados\"). A `<nav>` named \"Migas de pan\" (`breadcrumb` label) with an\n * `<ol>`: the levels above are links, the last one is plain text with\n * `aria-current=\"page\"`.\n *\n * ```tsx\n * <Breadcrumb>\n * <BreadcrumbItem render={<Link to=\"/programas\" />}>Programas especializados</BreadcrumbItem>\n * <BreadcrumbPage>Pérdida de peso</BreadcrumbPage>\n * </Breadcrumb>\n * ```\n *\n * The levels above are quiet (Label/Default in text-secondary, brand on hover), with\n * a chevron in border-strong between them, so the trail never competes with the\n * page title under it. The links are not underlined: inside the breadcrumb landmark\n * and its list, their position already tells they are links (WCAG 1.4.1 applies to\n * links in running text).\n *\n * Below the `lg` breakpoint only the level right above shows, as a way back with an\n * arrow (\"‹ Programas especializados\").\n */\nexport function Breadcrumb({\n \"aria-label\": ariaLabel,\n className,\n children,\n ...props\n}: BreadcrumbProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n return (\n <nav\n data-slot=\"breadcrumb\"\n aria-label={ariaLabel ?? labels.breadcrumb}\n className={className}\n {...props}\n >\n <ol\n className={cn(\n \"flex flex-wrap items-center gap-2\",\n // Mobile: only the parent level (the second-to-last item) stays.\n \"max-lg:[&>li:not(:nth-last-child(2))]:hidden\",\n )}\n >\n {children}\n </ol>\n </nav>\n );\n}\n\nexport interface BreadcrumbItemProps extends useRender.ComponentProps<\"a\"> {\n /** The level's name, the same as the section or page it links to. */\n children: ReactNode;\n}\n\n/**\n * A level above the current page: a link (`href`, or the router's with `render`)\n * followed by a chevron. On mobile, the parent level gets a back arrow in front\n * instead.\n */\nexport function BreadcrumbItem({\n render,\n ref,\n className,\n children,\n ...props\n}: BreadcrumbItemProps): React.JSX.Element {\n const link = useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n \"data-slot\": \"breadcrumb-link\",\n className: cn(\n \"focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary transition-colors hover:text-text-brand\",\n className,\n ),\n children,\n ...props,\n },\n });\n\n return (\n <li data-slot=\"breadcrumb-item\" className=\"flex items-center gap-2\">\n <ChevronLeftIcon size=\"sm\" className=\"text-text-secondary lg:hidden\" />\n {link}\n <ChevronRightIcon\n size=\"sm\"\n className=\"text-border-strong max-lg:hidden\"\n />\n </li>\n );\n}\n\nexport interface BreadcrumbPageProps extends ComponentProps<\"span\"> {}\n\n/** The current level: text, not a link, with `aria-current=\"page\"`. Hidden on mobile. */\nexport function BreadcrumbPage({\n className,\n ...props\n}: BreadcrumbPageProps): React.JSX.Element {\n return (\n <li data-slot=\"breadcrumb-page\" className=\"flex items-center\">\n <span\n aria-current=\"page\"\n className={cn(\"text-label-strong text-text-primary\", className)}\n {...props}\n />\n </li>\n );\n}\n"],"names":[],"mappings":";;;;;;AAkCO,SAAS,WAAW;AAAA,EACzB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuC;AACrC,QAAM,SAAS,kBAAA;AAEf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,aAAa,OAAO;AAAA,MAChC;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,UAAA;AAAA,UAGD;AAAA,QAAA;AAAA,MAAA;AAAA,IACH;AAAA,EAAA;AAGN;AAYO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,QAAM,OAAO,UAAU;AAAA,IACrB;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,OAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EACL,CACD;AAED,SACE,qBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,2BACxC,UAAA;AAAA,IAAA,oBAAC,iBAAA,EAAgB,MAAK,MAAK,WAAU,iCAAgC;AAAA,IACpE;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACZ,GACF;AAEJ;AAKO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,SACE,oBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,qBACxC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,gBAAa;AAAA,MACb,WAAW,GAAG,uCAAuC,SAAS;AAAA,MAC7D,GAAG;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ;"}
1
+ {"version":3,"file":"breadcrumb.js","sources":["../../../src/components/breadcrumb/breadcrumb.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ChevronLeftIcon, ChevronRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BreadcrumbProps extends ComponentProps<\"nav\"> {\n /** `BreadcrumbItem`s for the levels above, then one `BreadcrumbPage` for the current one. */\n children: ReactNode;\n}\n\n/**\n * Breadcrumb for pages two or three levels deep (a programme inside \"Programas\n * especializados\"). A `<nav>` named \"Migas de pan\" (`breadcrumb` label) with an\n * `<ol>`: the levels above are links, the last one is plain text with\n * `aria-current=\"page\"`.\n *\n * ```tsx\n * <Breadcrumb>\n * <BreadcrumbItem render={<Link to=\"/programas\" />}>Programas especializados</BreadcrumbItem>\n * <BreadcrumbPage>Pérdida de peso</BreadcrumbPage>\n * </Breadcrumb>\n * ```\n *\n * The levels above are quiet (Label/Default in text-secondary, brand on hover), with\n * a chevron in border-strong between them, so the trail never competes with the\n * page title under it. The links are not underlined: inside the breadcrumb landmark\n * and its list, their position already tells they are links (WCAG 1.4.1 applies to\n * links in running text).\n *\n * Below the `lg` breakpoint only the level right above shows, as a way back with an\n * arrow (\"‹ Programas especializados\").\n */\nexport function Breadcrumb({\n \"aria-label\": ariaLabel,\n className,\n children,\n ...props\n}: BreadcrumbProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n return (\n <nav\n data-slot=\"breadcrumb\"\n aria-label={ariaLabel ?? labels.breadcrumb}\n className={className}\n {...props}\n >\n <ol\n className={cn(\n \"flex flex-wrap items-center gap-2\",\n // Mobile: only the parent level (the second-to-last item) stays.\n \"max-lg:[&>li:not(:nth-last-child(2))]:hidden\",\n )}\n >\n {children}\n </ol>\n </nav>\n );\n}\n\nexport interface BreadcrumbItemProps extends useRender.ComponentProps<\"a\"> {\n /** The level's name, the same as the section or page it links to. */\n children: ReactNode;\n}\n\n/**\n * A level above the current page: a link (`href`, or the router's with `render`)\n * followed by a chevron. On mobile, the parent level gets a back arrow in front\n * instead.\n */\nexport function BreadcrumbItem({\n render,\n ref,\n className,\n children,\n ...props\n}: BreadcrumbItemProps): React.JSX.Element {\n const link = useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n \"data-slot\": \"breadcrumb-link\",\n className: cn(\n \"focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary interactive hover:text-text-brand\",\n className,\n ),\n children,\n ...props,\n },\n });\n\n return (\n <li data-slot=\"breadcrumb-item\" className=\"flex items-center gap-2\">\n <ChevronLeftIcon size=\"sm\" className=\"text-text-secondary lg:hidden\" />\n {link}\n <ChevronRightIcon\n size=\"sm\"\n className=\"text-border-strong max-lg:hidden\"\n />\n </li>\n );\n}\n\nexport interface BreadcrumbPageProps extends ComponentProps<\"span\"> {}\n\n/** The current level: text, not a link, with `aria-current=\"page\"`. Hidden on mobile. */\nexport function BreadcrumbPage({\n className,\n ...props\n}: BreadcrumbPageProps): React.JSX.Element {\n return (\n <li data-slot=\"breadcrumb-page\" className=\"flex items-center\">\n <span\n aria-current=\"page\"\n className={cn(\"text-label-strong text-text-primary\", className)}\n {...props}\n />\n </li>\n );\n}\n"],"names":[],"mappings":";;;;;;AAkCO,SAAS,WAAW;AAAA,EACzB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuC;AACrC,QAAM,SAAS,kBAAA;AAEf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,aAAa,OAAO;AAAA,MAChC;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,UAAA;AAAA,UAGD;AAAA,QAAA;AAAA,MAAA;AAAA,IACH;AAAA,EAAA;AAGN;AAYO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,QAAM,OAAO,UAAU;AAAA,IACrB;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,OAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EACL,CACD;AAED,SACE,qBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,2BACxC,UAAA;AAAA,IAAA,oBAAC,iBAAA,EAAgB,MAAK,MAAK,WAAU,iCAAgC;AAAA,IACpE;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACZ,GACF;AAEJ;AAKO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,SACE,oBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,qBACxC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,gBAAa;AAAA,MACb,WAAW,GAAG,uCAAuC,SAAS;AAAA,MAC7D,GAAG;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ;"}
@@ -12,6 +12,7 @@ export interface ButtonProps extends Omit<BaseButton.Props, "className">, Button
12
12
  loading?: boolean;
13
13
  leadingIcon?: ReactNode;
14
14
  trailingIcon?: ReactNode;
15
+ hoverArrow?: boolean;
15
16
  className?: string;
16
17
  }
17
18
  /**
@@ -25,5 +26,5 @@ export interface ButtonProps extends Omit<BaseButton.Props, "className">, Button
25
26
  * The drawing is 40px (36 small) but the hit area is always 44px. Full width: pass
26
27
  * `className="w-full"`.
27
28
  */
28
- export declare function Button({ variant, size, disabled, loading, leadingIcon, trailingIcon, className, children, type, ...props }: ButtonProps): React.JSX.Element;
29
+ export declare function Button({ variant, size, disabled, loading, leadingIcon, trailingIcon, hoverArrow, className, children, type, ...props }: ButtonProps): React.JSX.Element;
29
30
  export {};
@@ -3,10 +3,12 @@ import { Button as Button$1 } from "@base-ui/react/button";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { cn } from "../../lib/cn.js";
5
5
  import { Spinner } from "../spinner/spinner.js";
6
+ import { HoverArrow } from "../hover-arrow/hover-arrow.js";
6
7
  const buttonVariants = cva(
7
8
  [
8
9
  "inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap",
9
- "rounded-md border border-transparent text-label-strong transition-[color,background-color,border-color,box-shadow]",
10
+ "hover-trigger rounded-md border border-transparent text-label-strong interactive pressable",
11
+ "[--hover-arrow-gap:--spacing(2)] [--hover-arrow-size:var(--spacing-icon-sm)] [--hover-arrow-space:--spacing(2)]",
10
12
  "focus-ring touch-target",
11
13
  "[&_svg]:shrink-0 [&_svg]:size-icon-sm",
12
14
  "data-disabled:cursor-not-allowed data-disabled:shadow-none aria-busy:cursor-progress"
@@ -14,11 +16,11 @@ const buttonVariants = cva(
14
16
  {
15
17
  variants: {
16
18
  variant: {
17
- primary: "bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong",
19
+ primary: "bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong not-data-disabled:hover:shadow-md",
18
20
  secondary: "border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-background",
19
21
  outline: "border-border bg-background text-text-primary shadow-xs not-data-disabled:hover:border-border-strong not-data-disabled:hover:bg-surface",
20
22
  ghost: "bg-transparent text-text-primary not-data-disabled:hover:bg-surface",
21
- destructive: "bg-error-strong text-text-inverse shadow-xs",
23
+ destructive: "bg-error-strong text-text-inverse shadow-xs not-data-disabled:hover:brightness-90",
22
24
  inverse: "bg-background text-text-brand shadow-xs not-data-disabled:hover:bg-surface",
23
25
  "inverse-ghost": "bg-transparent text-text-inverse not-data-disabled:hover:bg-overlay-light"
24
26
  },
@@ -74,6 +76,7 @@ function Button({
74
76
  loading = false,
75
77
  leadingIcon,
76
78
  trailingIcon,
79
+ hoverArrow = false,
77
80
  className,
78
81
  children,
79
82
  type = "button",
@@ -92,7 +95,8 @@ function Button({
92
95
  children: [
93
96
  loading ? /* @__PURE__ */ jsx(Spinner, { size: 16, label: null, className: "text-current" }) : leadingIcon,
94
97
  children,
95
- !loading && trailingIcon
98
+ !loading && trailingIcon,
99
+ hoverArrow && !loading && !disabled && /* @__PURE__ */ jsx(HoverArrow, {})
96
100
  ]
97
101
  }
98
102
  );
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","sources":["../../../src/components/button/button.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { Spinner } from \"../spinner\";\n\nexport const buttonVariants = cva(\n [\n \"inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap\",\n \"rounded-md border border-transparent text-label-strong transition-[color,background-color,border-color,box-shadow]\",\n \"focus-ring touch-target\",\n \"[&_svg]:shrink-0 [&_svg]:size-icon-sm\",\n \"data-disabled:cursor-not-allowed data-disabled:shadow-none aria-busy:cursor-progress\",\n ],\n {\n variants: {\n variant: {\n primary:\n \"bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong\",\n secondary:\n \"border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-background\",\n outline:\n \"border-border bg-background text-text-primary shadow-xs not-data-disabled:hover:border-border-strong not-data-disabled:hover:bg-surface\",\n ghost:\n \"bg-transparent text-text-primary not-data-disabled:hover:bg-surface\",\n destructive: \"bg-error-strong text-text-inverse shadow-xs\",\n inverse:\n \"bg-background text-text-brand shadow-xs not-data-disabled:hover:bg-surface\",\n \"inverse-ghost\":\n \"bg-transparent text-text-inverse not-data-disabled:hover:bg-overlay-light\",\n },\n size: {\n default: \"h-control-md px-4\",\n small: \"h-control-sm px-3\",\n },\n disabled: {\n true: \"\",\n false: \"\",\n },\n },\n // Disabled uses explicit colours, not opacity: an opacity can't be a token and it\n // also dims the border.\n compoundVariants: [\n {\n variant: [\"primary\", \"destructive\"],\n disabled: true,\n className: \"bg-surface-raised text-text-disabled\",\n },\n {\n variant: [\"secondary\", \"outline\"],\n disabled: true,\n className: \"border-border-subtle bg-surface text-text-disabled\",\n },\n {\n variant: \"ghost\",\n disabled: true,\n className: \"text-text-disabled\",\n },\n {\n variant: \"inverse\",\n disabled: true,\n className: \"bg-border-inverse text-text-inverse-secondary\",\n },\n {\n variant: \"inverse-ghost\",\n disabled: true,\n className: \"text-text-inverse-secondary\",\n },\n ],\n defaultVariants: {\n variant: \"primary\",\n size: \"default\",\n disabled: false,\n },\n },\n);\n\ntype ButtonVariantProps = Omit<VariantProps<typeof buttonVariants>, \"disabled\">;\n\nexport interface ButtonProps\n extends Omit<BaseButton.Props, \"className\">,\n ButtonVariantProps {\n /** Keeps the variant colour, shows a spinner and ignores clicks without losing focus. */\n loading?: boolean;\n leadingIcon?: ReactNode;\n trailingIcon?: ReactNode;\n className?: string;\n}\n\n/**\n * Action button. A button ACTS; to navigate use `Link` (or `render={<a href />}` when\n * it has to look like a button).\n *\n * Hierarchy, from most to least weight: primary → secondary → outline → ghost.\n * `destructive` is a warning, not a level. `inverse` and `inverse-ghost` are only\n * for dark surfaces (`bg-brand-dark`). One primary action per block.\n *\n * The drawing is 40px (36 small) but the hit area is always 44px. Full width: pass\n * `className=\"w-full\"`.\n */\nexport function Button({\n variant,\n size,\n disabled = false,\n loading = false,\n leadingIcon,\n trailingIcon,\n className,\n children,\n type = \"button\",\n ...props\n}: ButtonProps): React.JSX.Element {\n return (\n <BaseButton\n data-slot=\"button\"\n type={type}\n disabled={disabled || loading}\n focusableWhenDisabled={loading}\n aria-busy={loading || undefined}\n className={cn(buttonVariants({ variant, size, disabled }), className)}\n {...props}\n >\n {loading ? (\n <Spinner size={16} label={null} className=\"text-current\" />\n ) : (\n leadingIcon\n )}\n {children}\n {!loading && trailingIcon}\n </BaseButton>\n );\n}\n"],"names":["BaseButton"],"mappings":";;;;;AAOO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,WACE;AAAA,QACF,SACE;AAAA,QACF,OACE;AAAA,QACF,aAAa;AAAA,QACb,SACE;AAAA,QACF,iBACE;AAAA,MAAA;AAAA,MAEJ,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,MAAA;AAAA,MAET,UAAU;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,IACT;AAAA;AAAA;AAAA,IAIF,kBAAkB;AAAA,MAChB;AAAA,QACE,SAAS,CAAC,WAAW,aAAa;AAAA,QAClC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS,CAAC,aAAa,SAAS;AAAA,QAChC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AAyBO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,GAAG;AACL,GAAmC;AACjC,SACE;AAAA,IAACA;AAAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,UAAU,YAAY;AAAA,MACtB,uBAAuB;AAAA,MACvB,aAAW,WAAW;AAAA,MACtB,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,SAAA,CAAU,GAAG,SAAS;AAAA,MACnE,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA,UACC,oBAAC,WAAQ,MAAM,IAAI,OAAO,MAAM,WAAU,gBAAe,IAEzD;AAAA,QAED;AAAA,QACA,CAAC,WAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnB;"}
1
+ {"version":3,"file":"button.js","sources":["../../../src/components/button/button.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { HoverArrow } from \"../hover-arrow\";\nimport { Spinner } from \"../spinner\";\n\nexport const buttonVariants = cva(\n [\n \"inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap\",\n \"hover-trigger rounded-md border border-transparent text-label-strong interactive pressable\",\n \"[--hover-arrow-gap:--spacing(2)] [--hover-arrow-size:var(--spacing-icon-sm)] [--hover-arrow-space:--spacing(2)]\",\n \"focus-ring touch-target\",\n \"[&_svg]:shrink-0 [&_svg]:size-icon-sm\",\n \"data-disabled:cursor-not-allowed data-disabled:shadow-none aria-busy:cursor-progress\",\n ],\n {\n variants: {\n variant: {\n primary:\n \"bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong not-data-disabled:hover:shadow-md\",\n secondary:\n \"border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-background\",\n outline:\n \"border-border bg-background text-text-primary shadow-xs not-data-disabled:hover:border-border-strong not-data-disabled:hover:bg-surface\",\n ghost:\n \"bg-transparent text-text-primary not-data-disabled:hover:bg-surface\",\n destructive:\n \"bg-error-strong text-text-inverse shadow-xs not-data-disabled:hover:brightness-90\",\n inverse:\n \"bg-background text-text-brand shadow-xs not-data-disabled:hover:bg-surface\",\n \"inverse-ghost\":\n \"bg-transparent text-text-inverse not-data-disabled:hover:bg-overlay-light\",\n },\n size: {\n default: \"h-control-md px-4\",\n small: \"h-control-sm px-3\",\n },\n disabled: {\n true: \"\",\n false: \"\",\n },\n },\n // Disabled uses explicit colours, not opacity: an opacity can't be a token and it\n // also dims the border.\n compoundVariants: [\n {\n variant: [\"primary\", \"destructive\"],\n disabled: true,\n className: \"bg-surface-raised text-text-disabled\",\n },\n {\n variant: [\"secondary\", \"outline\"],\n disabled: true,\n className: \"border-border-subtle bg-surface text-text-disabled\",\n },\n {\n variant: \"ghost\",\n disabled: true,\n className: \"text-text-disabled\",\n },\n {\n variant: \"inverse\",\n disabled: true,\n className: \"bg-border-inverse text-text-inverse-secondary\",\n },\n {\n variant: \"inverse-ghost\",\n disabled: true,\n className: \"text-text-inverse-secondary\",\n },\n ],\n defaultVariants: {\n variant: \"primary\",\n size: \"default\",\n disabled: false,\n },\n },\n);\n\ntype ButtonVariantProps = Omit<VariantProps<typeof buttonVariants>, \"disabled\">;\n\nexport interface ButtonProps\n extends Omit<BaseButton.Props, \"className\">,\n ButtonVariantProps {\n /** Keeps the variant colour, shows a spinner and ignores clicks without losing focus. */\n loading?: boolean;\n leadingIcon?: ReactNode;\n trailingIcon?: ReactNode;\n hoverArrow?: boolean;\n className?: string;\n}\n\n/**\n * Action button. A button ACTS; to navigate use `Link` (or `render={<a href />}` when\n * it has to look like a button).\n *\n * Hierarchy, from most to least weight: primary → secondary → outline → ghost.\n * `destructive` is a warning, not a level. `inverse` and `inverse-ghost` are only\n * for dark surfaces (`bg-brand-dark`). One primary action per block.\n *\n * The drawing is 40px (36 small) but the hit area is always 44px. Full width: pass\n * `className=\"w-full\"`.\n */\nexport function Button({\n variant,\n size,\n disabled = false,\n loading = false,\n leadingIcon,\n trailingIcon,\n hoverArrow = false,\n className,\n children,\n type = \"button\",\n ...props\n}: ButtonProps): React.JSX.Element {\n return (\n <BaseButton\n data-slot=\"button\"\n type={type}\n disabled={disabled || loading}\n focusableWhenDisabled={loading}\n aria-busy={loading || undefined}\n className={cn(buttonVariants({ variant, size, disabled }), className)}\n {...props}\n >\n {loading ? (\n <Spinner size={16} label={null} className=\"text-current\" />\n ) : (\n leadingIcon\n )}\n {children}\n {!loading && trailingIcon}\n {hoverArrow && !loading && !disabled && <HoverArrow />}\n </BaseButton>\n );\n}\n"],"names":["BaseButton"],"mappings":";;;;;;AAQO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,WACE;AAAA,QACF,SACE;AAAA,QACF,OACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,QACF,iBACE;AAAA,MAAA;AAAA,MAEJ,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,MAAA;AAAA,MAET,UAAU;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,IACT;AAAA;AAAA;AAAA,IAIF,kBAAkB;AAAA,MAChB;AAAA,QACE,SAAS,CAAC,WAAW,aAAa;AAAA,QAClC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS,CAAC,aAAa,SAAS;AAAA,QAChC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AA0BO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,GAAG;AACL,GAAmC;AACjC,SACE;AAAA,IAACA;AAAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,UAAU,YAAY;AAAA,MACtB,uBAAuB;AAAA,MACvB,aAAW,WAAW;AAAA,MACtB,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,SAAA,CAAU,GAAG,SAAS;AAAA,MACnE,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA,UACC,oBAAC,WAAQ,MAAM,IAAI,OAAO,MAAM,WAAU,gBAAe,IAEzD;AAAA,QAED;AAAA,QACA,CAAC,WAAW;AAAA,QACZ,cAAc,CAAC,WAAW,CAAC,gCAAa,YAAA,CAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG1D;"}
@@ -49,6 +49,7 @@ export interface CardFooterProps extends ComponentProps<"div"> {
49
49
  /** Where the card's single primary action goes. Its children share the width. */
50
50
  export declare function CardFooter({ className, ...props }: CardFooterProps): React.JSX.Element;
51
51
  export interface CardLinkProps extends useRender.ComponentProps<"a"> {
52
+ hoverArrow?: boolean;
52
53
  }
53
54
  /**
54
55
  * The link that makes a whole card navigable. It goes inside `CardHeader`'s title
@@ -56,7 +57,7 @@ export interface CardLinkProps extends useRender.ComponentProps<"a"> {
56
57
  * opened in a new tab and read as one link. Router links: `render={<Link to="…" />}`.
57
58
  * Other controls in the card (the "⋯" menu, the footer) stay on top of it.
58
59
  */
59
- export declare function CardLink({ render, ref, className, ...props }: CardLinkProps): React.JSX.Element;
60
+ export declare function CardLink({ render, ref, className, hoverArrow, children, ...props }: CardLinkProps): React.JSX.Element;
60
61
  export interface CardListProps extends ComponentProps<"ul"> {
61
62
  }
62
63
  /**
@@ -1,10 +1,11 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useRender } from "@base-ui/react/use-render";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { InfoCircleIcon } from "../../icons/generated/info-circle.js";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { HoverArrow } from "../hover-arrow/hover-arrow.js";
6
7
  const cardVariants = cva(
7
- "relative flex min-w-0 flex-col gap-4 rounded-xl",
8
+ "relative flex min-w-0 flex-col gap-4 rounded-xl interactive hover-lift",
8
9
  {
9
10
  variants: {
10
11
  elevation: {
@@ -80,6 +81,8 @@ function CardLink({
80
81
  render,
81
82
  ref,
82
83
  className,
84
+ hoverArrow = false,
85
+ children,
83
86
  ...props
84
87
  }) {
85
88
  return useRender({
@@ -89,10 +92,14 @@ function CardLink({
89
92
  props: {
90
93
  "data-slot": "card-link",
91
94
  className: cn(
92
- "outline-none after:absolute after:inset-0 after:rounded-xl",
95
+ "hover-trigger outline-none interactive hover:text-text-brand after:absolute after:inset-0 after:rounded-xl",
93
96
  "focus-visible:after:outline-2 focus-visible:after:outline-border-focus focus-visible:after:outline-offset-2",
94
97
  className
95
98
  ),
99
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ children,
101
+ hoverArrow && /* @__PURE__ */ jsx(HoverArrow, {})
102
+ ] }),
96
103
  ...props
97
104
  }
98
105
  });
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","sources":["../../../src/components/card/card.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { InfoCircleIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\n\nexport const cardVariants = cva(\n \"relative flex min-w-0 flex-col gap-4 rounded-xl\",\n {\n variants: {\n elevation: {\n flat: \"border border-border-subtle bg-background\",\n raised: \"bg-background shadow-s\",\n filled: \"bg-surface\",\n },\n padding: {\n default: \"p-4\",\n large: \"p-6\",\n },\n },\n defaultVariants: {\n elevation: \"flat\",\n padding: \"default\",\n },\n },\n);\n\ntype CardVariantProps = VariantProps<typeof cardVariants>;\n\nexport type CardElevation = NonNullable<CardVariantProps[\"elevation\"]>;\n\nexport type CardPadding = NonNullable<CardVariantProps[\"padding\"]>;\n\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport interface CardProps extends ComponentProps<\"div\">, CardVariantProps {}\n\n/**\n * The container the Card family is built on (radius-xl, padding 16 or 24, one of\n * three elevations). Header, content and footer are parts, not props:\n * `<Card><CardHeader /> …children… <CardFooter /></Card>`.\n *\n * **Pick the elevation by what it sits on — pick wrong and the card disappears:**\n * - `flat` (default): white with a 1px border, on a light `surface`. Without the\n * border, white on surface is 1.07:1.\n * - `filled`: `surface` fill, no border, on a white background.\n * - `raised`: white with `shadow-s`, only for what really floats (a dropdown, a\n * draggable card). Eight shadowed cards in a list rank nothing, they're just noise.\n *\n * A Card is not interactive. If the whole card navigates, put a `CardLink` in the\n * title (a real link stretched over the card), never an `onClick` on the `<div>`.\n *\n * Not for full-bleed images: the padding lives in the container. Don't zero it.\n */\nexport function Card({\n elevation,\n padding,\n className,\n ...props\n}: CardProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card\"\n className={cn(cardVariants({ elevation, padding }), className)}\n {...props}\n />\n );\n}\n\nexport interface CardHeaderProps extends Omit<ComponentProps<\"div\">, \"title\"> {\n /** Heading/h4 look. Put a `CardLink` inside when the whole card navigates. */\n title: ReactNode;\n /**\n * Heading level for the outline (h2–h6). The look doesn't change; the level comes\n * from where the card sits in the page. Default 3.\n */\n headingLevel?: CardHeadingLevel;\n /**\n * The \"⋯\" overflow menu (a `Menu` with a ghost small icon trigger). One primary\n * action per block: the primary goes in `CardFooter`, everything else here.\n */\n action?: ReactNode;\n}\n\nexport function CardHeader({\n title,\n headingLevel = 3,\n action,\n className,\n ...props\n}: CardHeaderProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\"flex min-w-0 items-center gap-2\", className)}\n {...props}\n >\n <Heading className=\"min-w-0 flex-1 text-heading-h4 text-text-primary\">\n {title}\n </Heading>\n {action && (\n // Above a stretched CardLink so it stays clickable.\n <div className=\"relative z-10 -my-2 flex shrink-0\">{action}</div>\n )}\n </div>\n );\n}\n\nexport interface CardFooterProps extends ComponentProps<\"div\"> {}\n\n/** Where the card's single primary action goes. Its children share the width. */\nexport function CardFooter({\n className,\n ...props\n}: CardFooterProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\n \"relative z-10 flex items-center gap-2 *:flex-1\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface CardLinkProps extends useRender.ComponentProps<\"a\"> {}\n\n/**\n * The link that makes a whole card navigable. It goes inside `CardHeader`'s title\n * and stretches over the card with a pseudo-element, so it can still be copied,\n * opened in a new tab and read as one link. Router links: `render={<Link to=\"…\" />}`.\n * Other controls in the card (the \"⋯\" menu, the footer) stay on top of it.\n */\nexport function CardLink({\n render,\n ref,\n className,\n ...props\n}: CardLinkProps): React.JSX.Element {\n return useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n \"data-slot\": \"card-link\",\n className: cn(\n \"outline-none after:absolute after:inset-0 after:rounded-xl\",\n \"focus-visible:after:outline-2 focus-visible:after:outline-border-focus focus-visible:after:outline-offset-2\",\n className,\n ),\n ...props,\n },\n });\n}\n\nexport interface CardListProps extends ComponentProps<\"ul\"> {}\n\n/**\n * Card content for a short list: 1 to 4 `ListRow`s (a consultation's documents, the\n * next appointments). With more than four, it isn't a card: use a list or a page.\n */\nexport function CardList({\n className,\n ...props\n}: CardListProps): React.JSX.Element {\n return (\n <ul\n data-slot=\"card-list\"\n className={cn(\"flex flex-col\", className)}\n {...props}\n />\n );\n}\n\nexport interface CardCalloutProps\n extends Omit<ComponentProps<\"div\">, \"children\">,\n Pick<CardVariantProps, \"elevation\"> {\n /** One short sentence (\"Usa el chat para enviar el motivo de consulta…\"). */\n message: ReactNode;\n /** Decorative, in `text-secondary`: the text carries the message. Default `info-circle`. */\n icon?: ReactNode;\n /** One `Button`, full width (\"Chatear con la profesional\"). */\n action?: ReactNode;\n}\n\n/**\n * A card with a short hint and ONE action, full width: waiting room, end of the\n * video call (\"Puedes chatear con tu profesional hasta 48 horas después de la cita\").\n *\n * It is not a Banner: a Banner reports a state (error, warning); this invites you to\n * do something. Raised by default, as in Figma; follow the Card elevation rule if it\n * sits on white.\n */\nexport function CardCallout({\n message,\n icon = <InfoCircleIcon />,\n action,\n elevation = \"raised\",\n className,\n ...props\n}: CardCalloutProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card-callout\"\n className={cn(\n cardVariants({ elevation, padding: \"default\" }),\n \"gap-3\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-start gap-2\">\n <span\n aria-hidden\n className=\"flex h-5 shrink-0 items-center text-text-secondary [&_svg]:size-icon-md\"\n >\n {icon}\n </span>\n <p className=\"min-w-0 flex-1 text-body-small text-text-secondary\">\n {message}\n </p>\n </div>\n {action && <div className=\"flex *:flex-1\">{action}</div>}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AAOO,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,WAAW;AAAA,QACT,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ;AAAA,MAAA;AAAA,MAEV,SAAS;AAAA,QACP,SAAS;AAAA,QACT,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,iBAAiB;AAAA,MACf,WAAW;AAAA,MACX,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;AA6BO,SAAS,KAAK;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiC;AAC/B,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,EAAE,WAAW,QAAA,CAAS,GAAG,SAAS;AAAA,MAC5D,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;AAiBO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuC;AACrC,QAAM,UAAU,IAAI,YAAY;AAEhC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,mCAAmC,SAAS;AAAA,MACzD,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,SAAA,EAAQ,WAAU,oDAChB,UAAA,OACH;AAAA,QACC;AAAA,QAEC,oBAAC,OAAA,EAAI,WAAU,qCAAqC,UAAA,OAAA,CAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAInE;AAKO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,GAAG;AACL,GAAuC;AACrC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;AAUO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqC;AACnC,SAAO,UAAU;AAAA,IACf;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,OAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,GAAG;AAAA,IAAA;AAAA,EACL,CACD;AACH;AAQO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,GAAG;AACL,GAAqC;AACnC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,iBAAiB,SAAS;AAAA,MACvC,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;AAqBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,2BAAQ,gBAAA,EAAe;AAAA,EACvB;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,GAAG;AACL,GAAwC;AACtC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT,aAAa,EAAE,WAAW,SAAS,WAAW;AAAA,QAC9C;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,eAAW;AAAA,cACX,WAAU;AAAA,cAET,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAEH,oBAAC,KAAA,EAAE,WAAU,sDACV,UAAA,QAAA,CACH;AAAA,QAAA,GACF;AAAA,QACC,UAAU,oBAAC,OAAA,EAAI,WAAU,iBAAiB,UAAA,OAAA,CAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGxD;"}
1
+ {"version":3,"file":"card.js","sources":["../../../src/components/card/card.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { InfoCircleIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { HoverArrow } from \"../hover-arrow\";\n\nexport const cardVariants = cva(\n \"relative flex min-w-0 flex-col gap-4 rounded-xl interactive hover-lift\",\n {\n variants: {\n elevation: {\n flat: \"border border-border-subtle bg-background\",\n raised: \"bg-background shadow-s\",\n filled: \"bg-surface\",\n },\n padding: {\n default: \"p-4\",\n large: \"p-6\",\n },\n },\n defaultVariants: {\n elevation: \"flat\",\n padding: \"default\",\n },\n },\n);\n\ntype CardVariantProps = VariantProps<typeof cardVariants>;\n\nexport type CardElevation = NonNullable<CardVariantProps[\"elevation\"]>;\n\nexport type CardPadding = NonNullable<CardVariantProps[\"padding\"]>;\n\nexport type CardHeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport interface CardProps extends ComponentProps<\"div\">, CardVariantProps {}\n\n/**\n * The container the Card family is built on (radius-xl, padding 16 or 24, one of\n * three elevations). Header, content and footer are parts, not props:\n * `<Card><CardHeader /> …children… <CardFooter /></Card>`.\n *\n * **Pick the elevation by what it sits on — pick wrong and the card disappears:**\n * - `flat` (default): white with a 1px border, on a light `surface`. Without the\n * border, white on surface is 1.07:1.\n * - `filled`: `surface` fill, no border, on a white background.\n * - `raised`: white with `shadow-s`, only for what really floats (a dropdown, a\n * draggable card). Eight shadowed cards in a list rank nothing, they're just noise.\n *\n * A Card is not interactive. If the whole card navigates, put a `CardLink` in the\n * title (a real link stretched over the card), never an `onClick` on the `<div>`.\n *\n * Not for full-bleed images: the padding lives in the container. Don't zero it.\n */\nexport function Card({\n elevation,\n padding,\n className,\n ...props\n}: CardProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card\"\n className={cn(cardVariants({ elevation, padding }), className)}\n {...props}\n />\n );\n}\n\nexport interface CardHeaderProps extends Omit<ComponentProps<\"div\">, \"title\"> {\n /** Heading/h4 look. Put a `CardLink` inside when the whole card navigates. */\n title: ReactNode;\n /**\n * Heading level for the outline (h2–h6). The look doesn't change; the level comes\n * from where the card sits in the page. Default 3.\n */\n headingLevel?: CardHeadingLevel;\n /**\n * The \"⋯\" overflow menu (a `Menu` with a ghost small icon trigger). One primary\n * action per block: the primary goes in `CardFooter`, everything else here.\n */\n action?: ReactNode;\n}\n\nexport function CardHeader({\n title,\n headingLevel = 3,\n action,\n className,\n ...props\n}: CardHeaderProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\"flex min-w-0 items-center gap-2\", className)}\n {...props}\n >\n <Heading className=\"min-w-0 flex-1 text-heading-h4 text-text-primary\">\n {title}\n </Heading>\n {action && (\n // Above a stretched CardLink so it stays clickable.\n <div className=\"relative z-10 -my-2 flex shrink-0\">{action}</div>\n )}\n </div>\n );\n}\n\nexport interface CardFooterProps extends ComponentProps<\"div\"> {}\n\n/** Where the card's single primary action goes. Its children share the width. */\nexport function CardFooter({\n className,\n ...props\n}: CardFooterProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\n \"relative z-10 flex items-center gap-2 *:flex-1\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface CardLinkProps extends useRender.ComponentProps<\"a\"> {\n hoverArrow?: boolean;\n}\n\n/**\n * The link that makes a whole card navigable. It goes inside `CardHeader`'s title\n * and stretches over the card with a pseudo-element, so it can still be copied,\n * opened in a new tab and read as one link. Router links: `render={<Link to=\"…\" />}`.\n * Other controls in the card (the \"⋯\" menu, the footer) stay on top of it.\n */\nexport function CardLink({\n render,\n ref,\n className,\n hoverArrow = false,\n children,\n ...props\n}: CardLinkProps): React.JSX.Element {\n return useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n \"data-slot\": \"card-link\",\n className: cn(\n \"hover-trigger outline-none interactive hover:text-text-brand after:absolute after:inset-0 after:rounded-xl\",\n \"focus-visible:after:outline-2 focus-visible:after:outline-border-focus focus-visible:after:outline-offset-2\",\n className,\n ),\n children: (\n <>\n {children}\n {hoverArrow && <HoverArrow />}\n </>\n ),\n ...props,\n },\n });\n}\n\nexport interface CardListProps extends ComponentProps<\"ul\"> {}\n\n/**\n * Card content for a short list: 1 to 4 `ListRow`s (a consultation's documents, the\n * next appointments). With more than four, it isn't a card: use a list or a page.\n */\nexport function CardList({\n className,\n ...props\n}: CardListProps): React.JSX.Element {\n return (\n <ul\n data-slot=\"card-list\"\n className={cn(\"flex flex-col\", className)}\n {...props}\n />\n );\n}\n\nexport interface CardCalloutProps\n extends Omit<ComponentProps<\"div\">, \"children\">,\n Pick<CardVariantProps, \"elevation\"> {\n /** One short sentence (\"Usa el chat para enviar el motivo de consulta…\"). */\n message: ReactNode;\n /** Decorative, in `text-secondary`: the text carries the message. Default `info-circle`. */\n icon?: ReactNode;\n /** One `Button`, full width (\"Chatear con la profesional\"). */\n action?: ReactNode;\n}\n\n/**\n * A card with a short hint and ONE action, full width: waiting room, end of the\n * video call (\"Puedes chatear con tu profesional hasta 48 horas después de la cita\").\n *\n * It is not a Banner: a Banner reports a state (error, warning); this invites you to\n * do something. Raised by default, as in Figma; follow the Card elevation rule if it\n * sits on white.\n */\nexport function CardCallout({\n message,\n icon = <InfoCircleIcon />,\n action,\n elevation = \"raised\",\n className,\n ...props\n}: CardCalloutProps): React.JSX.Element {\n return (\n <div\n data-slot=\"card-callout\"\n className={cn(\n cardVariants({ elevation, padding: \"default\" }),\n \"gap-3\",\n className,\n )}\n {...props}\n >\n <div className=\"flex items-start gap-2\">\n <span\n aria-hidden\n className=\"flex h-5 shrink-0 items-center text-text-secondary [&_svg]:size-icon-md\"\n >\n {icon}\n </span>\n <p className=\"min-w-0 flex-1 text-body-small text-text-secondary\">\n {message}\n </p>\n </div>\n {action && <div className=\"flex *:flex-1\">{action}</div>}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { cn } from "../../lib/cn.js";
3
3
  import { useMediCoreLabels } from "../../provider/medicore-provider.js";
4
4
  import { Badge } from "../badge/badge.js";
5
5
  import { CardLink } from "../card/card.js";
6
+ import { HoverArrow } from "../hover-arrow/hover-arrow.js";
6
7
  import { linkVariants } from "../link/link.js";
7
8
  function CardArticle({
8
9
  title,
@@ -22,7 +23,7 @@ function CardArticle({
22
23
  {
23
24
  "data-slot": "card-article",
24
25
  className: cn(
25
- "relative flex min-w-0 flex-col rounded-xl bg-background shadow-s",
26
+ "relative flex min-w-0 flex-col rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media",
26
27
  className
27
28
  ),
28
29
  ...props,
@@ -34,7 +35,10 @@ function CardArticle({
34
35
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-2 p-4", children: [
35
36
  /* @__PURE__ */ jsx(Heading, { className: "text-heading-h4 text-text-primary", children: href || render ? /* @__PURE__ */ jsx(CardLink, { href, render, children: title }) : title }),
36
37
  excerpt && /* @__PURE__ */ jsx("p", { className: "text-body-small text-text-secondary", children: excerpt }),
37
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: linkVariants(), children: labels.articleRead })
38
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": true, className: linkVariants(), children: [
39
+ labels.articleRead,
40
+ /* @__PURE__ */ jsx(HoverArrow, {})
41
+ ] })
38
42
  ] })
39
43
  ]
40
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"card-article.js","sources":["../../../src/components/card-article/card-article.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\nimport { Badge } from \"../badge\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\nimport { linkVariants } from \"../link\";\n\nexport interface CardArticleProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** Informative, with no promise of results. Heading/h4 look; the link's name. */\n title: ReactNode;\n /** Two or three lines. */\n excerpt?: ReactNode;\n /** The article's category as a brand Badge on the image (\"Pérdida de peso\"). */\n category?: ReactNode;\n /** `<img src=\"…\" alt=\"\" />`, cropped to fill 200px. */\n image?: ReactNode;\n /** The article. The whole card is this link. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Level of the title's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\n/**\n * The featured article of \"Te puede interesar\". The other articles go as\n * `ListRow`s with a thumbnail and the category as overline.\n *\n * The whole card links (a `CardLink` in the title). \"Leer artículo\"\n * (`articleRead` label) is only the visual cue: it looks like a link but it isn't a\n * second one.\n */\nexport function CardArticle({\n title,\n excerpt,\n category,\n image,\n href,\n render,\n headingLevel = 3,\n className,\n ...props\n}: CardArticleProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n const Heading = `h${headingLevel}` as const;\n\n return (\n <article\n data-slot=\"card-article\"\n className={cn(\n \"relative flex min-w-0 flex-col rounded-xl bg-background shadow-s\",\n className,\n )}\n {...props}\n >\n <div className=\"relative h-50 shrink-0 overflow-hidden rounded-t-xl bg-brand-subtle [&>img]:size-full [&>img]:object-cover\">\n {image}\n {category && (\n <Badge variant=\"brand\" className=\"absolute top-3 left-3\">\n {category}\n </Badge>\n )}\n </div>\n <div className=\"flex flex-col items-start gap-2 p-4\">\n <Heading className=\"text-heading-h4 text-text-primary\">\n {href || render ? (\n <CardLink href={href} render={render}>\n {title}\n </CardLink>\n ) : (\n title\n )}\n </Heading>\n {excerpt && (\n <p className=\"text-body-small text-text-secondary\">{excerpt}</p>\n )}\n <span aria-hidden className={linkVariants()}>\n {labels.articleRead}\n </span>\n </div>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;;;AAmCO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,GAAG;AACL,GAAwC;AACtC,QAAM,SAAS,kBAAA;AACf,QAAM,UAAU,IAAI,YAAY;AAEhC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,8GACZ,UAAA;AAAA,UAAA;AAAA,UACA,YACC,oBAAC,OAAA,EAAM,SAAQ,SAAQ,WAAU,yBAC9B,UAAA,SAAA,CACH;AAAA,QAAA,GAEJ;AAAA,QACA,qBAAC,OAAA,EAAI,WAAU,uCACb,UAAA;AAAA,UAAA,oBAAC,SAAA,EAAQ,WAAU,qCAChB,UAAA,QAAQ,SACP,oBAAC,UAAA,EAAS,MAAY,QACnB,UAAA,MAAA,CACH,IAEA,OAEJ;AAAA,UACC,WACC,oBAAC,KAAA,EAAE,WAAU,uCAAuC,UAAA,SAAQ;AAAA,UAE9D,oBAAC,UAAK,eAAW,MAAC,WAAW,gBAC1B,iBAAO,YAAA,CACV;AAAA,QAAA,EAAA,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
1
+ {"version":3,"file":"card-article.js","sources":["../../../src/components/card-article/card-article.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\nimport { Badge } from \"../badge\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\nimport { HoverArrow } from \"../hover-arrow\";\nimport { linkVariants } from \"../link\";\n\nexport interface CardArticleProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** Informative, with no promise of results. Heading/h4 look; the link's name. */\n title: ReactNode;\n /** Two or three lines. */\n excerpt?: ReactNode;\n /** The article's category as a brand Badge on the image (\"Pérdida de peso\"). */\n category?: ReactNode;\n /** `<img src=\"…\" alt=\"\" />`, cropped to fill 200px. */\n image?: ReactNode;\n /** The article. The whole card is this link. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Level of the title's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\n/**\n * The featured article of \"Te puede interesar\". The other articles go as\n * `ListRow`s with a thumbnail and the category as overline.\n *\n * The whole card links (a `CardLink` in the title). \"Leer artículo\"\n * (`articleRead` label) is only the visual cue: it looks like a link but it isn't a\n * second one.\n */\nexport function CardArticle({\n title,\n excerpt,\n category,\n image,\n href,\n render,\n headingLevel = 3,\n className,\n ...props\n}: CardArticleProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n const Heading = `h${headingLevel}` as const;\n\n return (\n <article\n data-slot=\"card-article\"\n className={cn(\n \"relative flex min-w-0 flex-col rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media\",\n className,\n )}\n {...props}\n >\n <div className=\"relative h-50 shrink-0 overflow-hidden rounded-t-xl bg-brand-subtle [&>img]:size-full [&>img]:object-cover\">\n {image}\n {category && (\n <Badge variant=\"brand\" className=\"absolute top-3 left-3\">\n {category}\n </Badge>\n )}\n </div>\n <div className=\"flex flex-col items-start gap-2 p-4\">\n <Heading className=\"text-heading-h4 text-text-primary\">\n {href || render ? (\n <CardLink href={href} render={render}>\n {title}\n </CardLink>\n ) : (\n title\n )}\n </Heading>\n {excerpt && (\n <p className=\"text-body-small text-text-secondary\">{excerpt}</p>\n )}\n <span aria-hidden className={linkVariants()}>\n {labels.articleRead}\n <HoverArrow />\n </span>\n </div>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAoCO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,GAAG;AACL,GAAwC;AACtC,QAAM,SAAS,kBAAA;AACf,QAAM,UAAU,IAAI,YAAY;AAEhC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,8GACZ,UAAA;AAAA,UAAA;AAAA,UACA,YACC,oBAAC,OAAA,EAAM,SAAQ,SAAQ,WAAU,yBAC9B,UAAA,SAAA,CACH;AAAA,QAAA,GAEJ;AAAA,QACA,qBAAC,OAAA,EAAI,WAAU,uCACb,UAAA;AAAA,UAAA,oBAAC,SAAA,EAAQ,WAAU,qCAChB,UAAA,QAAQ,SACP,oBAAC,UAAA,EAAS,MAAY,QACnB,UAAA,MAAA,CACH,IAEA,OAEJ;AAAA,UACC,WACC,oBAAC,KAAA,EAAE,WAAU,uCAAuC,UAAA,SAAQ;AAAA,+BAE7D,QAAA,EAAK,eAAW,MAAC,WAAW,gBAC1B,UAAA;AAAA,YAAA,OAAO;AAAA,gCACP,YAAA,CAAA,CAAW;AAAA,UAAA,EAAA,CACd;AAAA,QAAA,EAAA,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
@@ -19,7 +19,7 @@ function CardProfessionalMini({
19
19
  "data-slot": "card-professional-mini",
20
20
  className: cn(
21
21
  "relative flex min-w-0 flex-col items-center gap-2 rounded-xl bg-background p-4 text-center shadow-s",
22
- href || render ? "transition-colors hover:bg-surface" : void 0,
22
+ href || render ? "interactive hover-lift" : void 0,
23
23
  className
24
24
  ),
25
25
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"card-professional-mini.js","sources":["../../../src/components/card-professional-mini/card-professional-mini.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { Avatar } from \"../avatar\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\n\nexport interface CardProfessionalMiniProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** \"Dra. Paula García\". The card's heading. */\n name: ReactNode;\n /** \"Nº de colegiado 282873573\": their own, never a repeated placeholder number. */\n license: ReactNode;\n /** A real photo, always: never initials or an icon for a professional. */\n avatarSrc?: string;\n /** Their full profile (`CardProfessional`) when they have an agenda. The whole card links. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Level of the name's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\n/**\n * A professional of a programme's medical team: photo + name + licence number, the\n * first trust signal.\n */\nexport function CardProfessionalMini({\n name,\n license,\n avatarSrc,\n href,\n render,\n headingLevel = 3,\n className,\n ...props\n}: CardProfessionalMiniProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n\n return (\n <article\n data-slot=\"card-professional-mini\"\n className={cn(\n \"relative flex min-w-0 flex-col items-center gap-2 rounded-xl bg-background p-4 text-center shadow-s\",\n href || render ? \"transition-colors hover:bg-surface\" : undefined,\n className,\n )}\n {...props}\n >\n <Avatar size={56} src={avatarSrc} />\n <Heading className=\"text-label-strong text-text-primary\">\n {href || render ? (\n <CardLink href={href} render={render}>\n {name}\n </CardLink>\n ) : (\n name\n )}\n </Heading>\n <p className=\"text-label-small text-text-secondary\">{license}</p>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;AA2BO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,QAAM,UAAU,IAAI,YAAY;AAEhC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA,QAAQ,SAAS,uCAAuC;AAAA,QACxD;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAO,MAAM,IAAI,KAAK,WAAW;AAAA,QAClC,oBAAC,SAAA,EAAQ,WAAU,uCAChB,UAAA,QAAQ,SACP,oBAAC,UAAA,EAAS,MAAY,QACnB,UAAA,KAAA,CACH,IAEA,MAEJ;AAAA,QACA,oBAAC,KAAA,EAAE,WAAU,wCAAwC,UAAA,QAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnE;"}
1
+ {"version":3,"file":"card-professional-mini.js","sources":["../../../src/components/card-professional-mini/card-professional-mini.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { Avatar } from \"../avatar\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\n\nexport interface CardProfessionalMiniProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** \"Dra. Paula García\". The card's heading. */\n name: ReactNode;\n /** \"Nº de colegiado 282873573\": their own, never a repeated placeholder number. */\n license: ReactNode;\n /** A real photo, always: never initials or an icon for a professional. */\n avatarSrc?: string;\n /** Their full profile (`CardProfessional`) when they have an agenda. The whole card links. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Level of the name's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\n/**\n * A professional of a programme's medical team: photo + name + licence number, the\n * first trust signal.\n */\nexport function CardProfessionalMini({\n name,\n license,\n avatarSrc,\n href,\n render,\n headingLevel = 3,\n className,\n ...props\n}: CardProfessionalMiniProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n\n return (\n <article\n data-slot=\"card-professional-mini\"\n className={cn(\n \"relative flex min-w-0 flex-col items-center gap-2 rounded-xl bg-background p-4 text-center shadow-s\",\n href || render ? \"interactive hover-lift\" : undefined,\n className,\n )}\n {...props}\n >\n <Avatar size={56} src={avatarSrc} />\n <Heading className=\"text-label-strong text-text-primary\">\n {href || render ? (\n <CardLink href={href} render={render}>\n {name}\n </CardLink>\n ) : (\n name\n )}\n </Heading>\n <p className=\"text-label-small text-text-secondary\">{license}</p>\n </article>\n );\n}\n"],"names":[],"mappings":";;;;AA2BO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,QAAM,UAAU,IAAI,YAAY;AAEhC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA,QAAQ,SAAS,2BAA2B;AAAA,QAC5C;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAO,MAAM,IAAI,KAAK,WAAW;AAAA,QAClC,oBAAC,SAAA,EAAQ,WAAU,uCAChB,UAAA,QAAQ,SACP,oBAAC,UAAA,EAAS,MAAY,QACnB,UAAA,KAAA,CACH,IAEA,MAEJ;AAAA,QACA,oBAAC,KAAA,EAAE,WAAU,wCAAwC,UAAA,QAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnE;"}
@@ -63,7 +63,7 @@ function CardProgram({
63
63
  "data-slot": "card-program",
64
64
  "data-layout": "featured",
65
65
  className: cn(
66
- "@container relative min-w-0 rounded-xl bg-background shadow-s",
66
+ "@container relative min-w-0 rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media",
67
67
  className
68
68
  ),
69
69
  ...props,
@@ -97,7 +97,7 @@ function CardProgram({
97
97
  "data-slot": "card-program",
98
98
  "data-layout": "grid",
99
99
  className: cn(
100
- "@container relative flex min-w-0 flex-col rounded-xl bg-background shadow-s",
100
+ "@container relative flex min-w-0 flex-col rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media",
101
101
  className
102
102
  ),
103
103
  ...props,
@@ -127,7 +127,13 @@ function CardProgram({
127
127
  {
128
128
  "aria-hidden": true,
129
129
  className: "hidden size-7 shrink-0 items-center justify-center rounded-full bg-brand text-text-inverse @min-[240px]:flex",
130
- children: /* @__PURE__ */ jsx(ArrowNarrowRightIcon, { size: "sm" })
130
+ children: /* @__PURE__ */ jsx(
131
+ ArrowNarrowRightIcon,
132
+ {
133
+ size: "sm",
134
+ className: "interactive motion-safe:hover-triggered:translate-x-0.5"
135
+ }
136
+ )
131
137
  }
132
138
  )
133
139
  ] })
@@ -1 +1 @@
1
- {"version":3,"file":"card-program.js","sources":["../../../src/components/card-program/card-program.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ArrowNarrowRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { Badge } from \"../badge\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\n\nexport type CardProgramLayout = \"grid\" | \"featured\";\n\nexport interface CardProgramProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** \"Pérdida de peso\". The card's heading and the link's name. */\n title: ReactNode;\n /** One or two lines. Hidden in the compact (Mobile) card. */\n description?: ReactNode;\n /**\n * The live price of THIS clinic's page, es-ES format with a space: \"Desde 30 €\",\n * \"29,99 €\". Never another clinic's price.\n */\n price: ReactNode;\n /** \"Videoconsulta\". Shown after the price with a \"·\". Hidden in the compact card. */\n channel?: ReactNode;\n /** A real photo from mediQuo's image line: `<img src=\"…\" alt=\"\" />` if it adds nothing. */\n image?: ReactNode;\n /** \"Tratamiento destacado\": a brand Badge (on the image in Grid, above the title in Featured). */\n badge?: ReactNode;\n /** Featured only: a metric Badge next to `badge` (\"4,6/5 valoración\"). */\n metric?: ReactNode;\n /** The programme's page. The whole card is this link. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Featured only: the one action, a primary `Button` \"Reservar consulta\" (never \"Empezar tratamiento\"). */\n action?: ReactNode;\n /**\n * `grid` (default): the three-column grid; below 240px wide it becomes the compact\n * Mobile card (two-column grid on a phone) by itself. `featured`: the highlighted\n * programme, horizontal from 640px wide.\n */\n layout?: CardProgramLayout;\n /** Level of the title's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\nfunction ImageSlot({\n image,\n className,\n children,\n}: {\n image?: ReactNode;\n className?: string;\n children?: ReactNode;\n}): React.JSX.Element {\n return (\n <div\n className={cn(\n \"relative shrink-0 overflow-hidden bg-brand-subtle [&>img]:size-full [&>img]:object-cover\",\n className,\n )}\n >\n {image}\n {children}\n </div>\n );\n}\n\n/**\n * A specialised programme (Clínic). The whole card is the link to the programme's\n * page (a `CardLink` in the title); the arrow is decorative. One action.\n *\n * Figma `Layout=Mobile` is not a value: the `grid` card turns compact (no\n * description, no channel, no arrow) when its column is narrower than 240px.\n */\nexport function CardProgram({\n title,\n description,\n price,\n channel,\n image,\n badge,\n metric,\n href,\n render,\n action,\n layout = \"grid\",\n headingLevel = 3,\n className,\n ...props\n}: CardProgramProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n const heading =\n href || render ? (\n <CardLink href={href} render={render}>\n {title}\n </CardLink>\n ) : (\n title\n );\n\n const priceRow = (\n <p className=\"flex min-w-0 flex-wrap items-baseline gap-1\">\n <span className=\"text-label-strong text-text-primary\">{price}</span>\n {channel && (\n <span\n className={cn(\n \"text-body-small text-text-secondary\",\n layout === \"grid\" && \"hidden @min-[240px]:inline\",\n )}\n >\n · {channel}\n </span>\n )}\n </p>\n );\n\n if (layout === \"featured\") {\n return (\n <article\n data-slot=\"card-program\"\n data-layout=\"featured\"\n className={cn(\n \"@container relative min-w-0 rounded-xl bg-background shadow-s\",\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col @min-[640px]:flex-row\">\n <ImageSlot\n image={image}\n className=\"h-40 rounded-t-xl @min-[640px]:h-auto @min-[640px]:min-h-60 @min-[640px]:w-1/2 @min-[640px]:rounded-tr-none @min-[640px]:rounded-l-xl\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col justify-center gap-4 p-6 @min-[640px]:p-8\">\n {(badge || metric) && (\n <div className=\"flex flex-wrap gap-2\">\n {badge && <Badge variant=\"brand\">{badge}</Badge>}\n {metric && <Badge>{metric}</Badge>}\n </div>\n )}\n <Heading className=\"text-heading-h2 text-text-primary\">\n {heading}\n </Heading>\n {description && (\n <p className=\"text-body-small text-text-secondary\">\n {description}\n </p>\n )}\n <div className=\"flex flex-wrap items-center justify-between gap-4\">\n {priceRow}\n {action && <div className=\"relative z-10 flex\">{action}</div>}\n </div>\n </div>\n </div>\n </article>\n );\n }\n\n return (\n <article\n data-slot=\"card-program\"\n data-layout=\"grid\"\n className={cn(\n \"@container relative flex min-w-0 flex-col rounded-xl bg-background shadow-s\",\n className,\n )}\n {...props}\n >\n <ImageSlot\n image={image}\n className=\"h-27.5 rounded-t-xl @min-[240px]:h-40\"\n >\n {badge && (\n <Badge\n variant=\"brand\"\n className=\"absolute top-3 left-3 hidden @min-[240px]:inline-flex\"\n >\n {badge}\n </Badge>\n )}\n </ImageSlot>\n <div className=\"flex flex-1 flex-col gap-2 p-3 @min-[240px]:p-4\">\n <Heading className=\"text-label-strong text-text-primary @min-[240px]:text-heading-h4\">\n {heading}\n </Heading>\n {description && (\n <p className=\"line-clamp-3 hidden text-body-small text-text-secondary @min-[240px]:block\">\n {description}\n </p>\n )}\n <div className=\"mt-auto flex items-center gap-2\">\n <div className=\"min-w-0 flex-1\">{priceRow}</div>\n <span\n aria-hidden\n className=\"hidden size-7 shrink-0 items-center justify-center rounded-full bg-brand text-text-inverse @min-[240px]:flex\"\n >\n <ArrowNarrowRightIcon size=\"sm\" />\n </span>\n </div>\n </div>\n </article>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"card-program.js","sources":["../../../src/components/card-program/card-program.tsx"],"sourcesContent":["import type { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ArrowNarrowRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { Badge } from \"../badge\";\nimport { type CardHeadingLevel, CardLink } from \"../card\";\n\nexport type CardProgramLayout = \"grid\" | \"featured\";\n\nexport interface CardProgramProps\n extends Omit<ComponentProps<\"article\">, \"title\"> {\n /** \"Pérdida de peso\". The card's heading and the link's name. */\n title: ReactNode;\n /** One or two lines. Hidden in the compact (Mobile) card. */\n description?: ReactNode;\n /**\n * The live price of THIS clinic's page, es-ES format with a space: \"Desde 30 €\",\n * \"29,99 €\". Never another clinic's price.\n */\n price: ReactNode;\n /** \"Videoconsulta\". Shown after the price with a \"·\". Hidden in the compact card. */\n channel?: ReactNode;\n /** A real photo from mediQuo's image line: `<img src=\"…\" alt=\"\" />` if it adds nothing. */\n image?: ReactNode;\n /** \"Tratamiento destacado\": a brand Badge (on the image in Grid, above the title in Featured). */\n badge?: ReactNode;\n /** Featured only: a metric Badge next to `badge` (\"4,6/5 valoración\"). */\n metric?: ReactNode;\n /** The programme's page. The whole card is this link. */\n href?: string;\n /** Router link: `render={<Link to=\"…\" />}`. */\n render?: useRender.RenderProp;\n /** Featured only: the one action, a primary `Button` \"Reservar consulta\" (never \"Empezar tratamiento\"). */\n action?: ReactNode;\n /**\n * `grid` (default): the three-column grid; below 240px wide it becomes the compact\n * Mobile card (two-column grid on a phone) by itself. `featured`: the highlighted\n * programme, horizontal from 640px wide.\n */\n layout?: CardProgramLayout;\n /** Level of the title's heading. Default 3. */\n headingLevel?: CardHeadingLevel;\n}\n\nfunction ImageSlot({\n image,\n className,\n children,\n}: {\n image?: ReactNode;\n className?: string;\n children?: ReactNode;\n}): React.JSX.Element {\n return (\n <div\n className={cn(\n \"relative shrink-0 overflow-hidden bg-brand-subtle [&>img]:size-full [&>img]:object-cover\",\n className,\n )}\n >\n {image}\n {children}\n </div>\n );\n}\n\n/**\n * A specialised programme (Clínic). The whole card is the link to the programme's\n * page (a `CardLink` in the title); the arrow is decorative. One action.\n *\n * Figma `Layout=Mobile` is not a value: the `grid` card turns compact (no\n * description, no channel, no arrow) when its column is narrower than 240px.\n */\nexport function CardProgram({\n title,\n description,\n price,\n channel,\n image,\n badge,\n metric,\n href,\n render,\n action,\n layout = \"grid\",\n headingLevel = 3,\n className,\n ...props\n}: CardProgramProps): React.JSX.Element {\n const Heading = `h${headingLevel}` as const;\n const heading =\n href || render ? (\n <CardLink href={href} render={render}>\n {title}\n </CardLink>\n ) : (\n title\n );\n\n const priceRow = (\n <p className=\"flex min-w-0 flex-wrap items-baseline gap-1\">\n <span className=\"text-label-strong text-text-primary\">{price}</span>\n {channel && (\n <span\n className={cn(\n \"text-body-small text-text-secondary\",\n layout === \"grid\" && \"hidden @min-[240px]:inline\",\n )}\n >\n · {channel}\n </span>\n )}\n </p>\n );\n\n if (layout === \"featured\") {\n return (\n <article\n data-slot=\"card-program\"\n data-layout=\"featured\"\n className={cn(\n \"@container relative min-w-0 rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media\",\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col @min-[640px]:flex-row\">\n <ImageSlot\n image={image}\n className=\"h-40 rounded-t-xl @min-[640px]:h-auto @min-[640px]:min-h-60 @min-[640px]:w-1/2 @min-[640px]:rounded-tr-none @min-[640px]:rounded-l-xl\"\n />\n <div className=\"flex min-w-0 flex-1 flex-col justify-center gap-4 p-6 @min-[640px]:p-8\">\n {(badge || metric) && (\n <div className=\"flex flex-wrap gap-2\">\n {badge && <Badge variant=\"brand\">{badge}</Badge>}\n {metric && <Badge>{metric}</Badge>}\n </div>\n )}\n <Heading className=\"text-heading-h2 text-text-primary\">\n {heading}\n </Heading>\n {description && (\n <p className=\"text-body-small text-text-secondary\">\n {description}\n </p>\n )}\n <div className=\"flex flex-wrap items-center justify-between gap-4\">\n {priceRow}\n {action && <div className=\"relative z-10 flex\">{action}</div>}\n </div>\n </div>\n </div>\n </article>\n );\n }\n\n return (\n <article\n data-slot=\"card-program\"\n data-layout=\"grid\"\n className={cn(\n \"@container relative flex min-w-0 flex-col rounded-xl bg-background shadow-s interactive hover-lift hover-zoom-media\",\n className,\n )}\n {...props}\n >\n <ImageSlot\n image={image}\n className=\"h-27.5 rounded-t-xl @min-[240px]:h-40\"\n >\n {badge && (\n <Badge\n variant=\"brand\"\n className=\"absolute top-3 left-3 hidden @min-[240px]:inline-flex\"\n >\n {badge}\n </Badge>\n )}\n </ImageSlot>\n <div className=\"flex flex-1 flex-col gap-2 p-3 @min-[240px]:p-4\">\n <Heading className=\"text-label-strong text-text-primary @min-[240px]:text-heading-h4\">\n {heading}\n </Heading>\n {description && (\n <p className=\"line-clamp-3 hidden text-body-small text-text-secondary @min-[240px]:block\">\n {description}\n </p>\n )}\n <div className=\"mt-auto flex items-center gap-2\">\n <div className=\"min-w-0 flex-1\">{priceRow}</div>\n <span\n aria-hidden\n className=\"hidden size-7 shrink-0 items-center justify-center rounded-full bg-brand text-text-inverse @min-[240px]:flex\"\n >\n <ArrowNarrowRightIcon\n size=\"sm\"\n className=\"interactive motion-safe:hover-triggered:translate-x-0.5\"\n />\n </span>\n </div>\n </div>\n </article>\n );\n}\n"],"names":[],"mappings":"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"}