@clubmed/trident-ui 2.0.0-beta.4 → 2.0.0-beta.40

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 (206) hide show
  1. package/chunks/Carousel.context.js +1548 -0
  2. package/chunks/Carousel.context.js.map +1 -0
  3. package/chunks/ChatMessage.js +14395 -0
  4. package/chunks/ChatMessage.js.map +1 -0
  5. package/chunks/DateField.js +177 -63
  6. package/chunks/DateField.js.map +1 -1
  7. package/chunks/Tooltip.js +4461 -0
  8. package/chunks/Tooltip.js.map +1 -0
  9. package/chunks/chunk.js +11 -4
  10. package/chunks/client.js +18953 -0
  11. package/chunks/client.js.map +1 -0
  12. package/examples/button-demo.js +2 -2
  13. package/examples/button-demo.js.map +1 -1
  14. package/examples/chat-input-demo.d.ts +1 -0
  15. package/examples/chat-input-demo.js +21 -0
  16. package/examples/chat-input-demo.js.map +1 -0
  17. package/examples/chat-message-demo.d.ts +1 -0
  18. package/examples/chat-message-demo.js +20 -0
  19. package/examples/chat-message-demo.js.map +1 -0
  20. package/examples/chat-typing-indicator-demo.d.ts +1 -0
  21. package/examples/chat-typing-indicator-demo.js +14 -0
  22. package/examples/chat-typing-indicator-demo.js.map +1 -0
  23. package/examples/chat-window-demo.d.ts +1 -0
  24. package/examples/chat-window-demo.js +45 -0
  25. package/examples/chat-window-demo.js.map +1 -0
  26. package/examples/checkbox-demo.js +16 -20
  27. package/examples/checkbox-demo.js.map +1 -1
  28. package/examples/checkbox-select-demo.d.ts +1 -0
  29. package/examples/checkbox-select-demo.js +101 -0
  30. package/examples/checkbox-select-demo.js.map +1 -0
  31. package/examples/checkboxes-demo.js +6 -6
  32. package/examples/checkboxes-demo.js.map +1 -1
  33. package/examples/checkboxes-with-form-control-demo.js +4 -4
  34. package/examples/choice-expander-demo.js +4 -67
  35. package/examples/choice-expander-demo.js.map +1 -1
  36. package/examples/dropdown-demo.js +9 -1
  37. package/examples/dropdown-demo.js.map +1 -1
  38. package/examples/elastic-height-demo.js +2 -1
  39. package/examples/elastic-height-demo.js.map +1 -1
  40. package/examples/frame-demo.d.ts +1 -0
  41. package/examples/frame-demo.js +36 -0
  42. package/examples/frame-demo.js.map +1 -0
  43. package/examples/frame-horizontal-demo.d.ts +1 -0
  44. package/examples/frame-horizontal-demo.js +44 -0
  45. package/examples/frame-horizontal-demo.js.map +1 -0
  46. package/examples/frame-no-image-demo.d.ts +1 -0
  47. package/examples/frame-no-image-demo.js +47 -0
  48. package/examples/frame-no-image-demo.js.map +1 -0
  49. package/examples/frame-vertical-demo.d.ts +1 -0
  50. package/examples/frame-vertical-demo.js +44 -0
  51. package/examples/frame-vertical-demo.js.map +1 -0
  52. package/examples/frame-with-tag-demo.d.ts +1 -0
  53. package/examples/frame-with-tag-demo.js +48 -0
  54. package/examples/frame-with-tag-demo.js.map +1 -0
  55. package/examples/scrollbar-demo.d.ts +1 -0
  56. package/examples/scrollbar-demo.js +40 -0
  57. package/examples/scrollbar-demo.js.map +1 -0
  58. package/examples/slider-frame-demo.d.ts +1 -0
  59. package/examples/slider-frame-demo.js +38 -0
  60. package/examples/slider-frame-demo.js.map +1 -0
  61. package/examples/slider-frame-with-button-demo.d.ts +1 -0
  62. package/examples/slider-frame-with-button-demo.js +46 -0
  63. package/examples/slider-frame-with-button-demo.js.map +1 -0
  64. package/examples/slider-frame-with-tag-demo.d.ts +1 -0
  65. package/examples/slider-frame-with-tag-demo.js +50 -0
  66. package/examples/slider-frame-with-tag-demo.js.map +1 -0
  67. package/examples/switch-demo.js +1 -1
  68. package/examples/switch-demo.js.map +1 -1
  69. package/examples/tooltip-demo.d.ts +1 -0
  70. package/examples/tooltip-demo.js +103 -0
  71. package/examples/tooltip-demo.js.map +1 -0
  72. package/package.json +10 -3
  73. package/styles/animate.css +19 -19
  74. package/styles/components.css +82 -0
  75. package/styles/theme.css +23 -18
  76. package/styles/ui/button.css +19 -25
  77. package/styles/ui/chat-button.css +68 -1
  78. package/styles/ui/controls.css +9 -63
  79. package/styles/ui/range.css +1 -1
  80. package/styles/variants.css +0 -2
  81. package/ui/AdvancedToast.js +11 -11
  82. package/ui/AdvancedToast.js.map +1 -1
  83. package/ui/BasicToast.js +1 -1
  84. package/ui/BasicToast.js.map +1 -1
  85. package/ui/Breadcrumb.d.ts +2 -2
  86. package/ui/Breadcrumb.js +31 -35
  87. package/ui/Breadcrumb.js.map +1 -1
  88. package/ui/ChatButton.js +1 -1
  89. package/ui/ChatButton.js.map +1 -1
  90. package/ui/ChatInput.d.ts +10 -0
  91. package/ui/ChatInput.js +149 -0
  92. package/ui/ChatInput.js.map +1 -0
  93. package/ui/ChatMessage.d.ts +6 -0
  94. package/ui/ChatMessage.js +2 -0
  95. package/ui/ChatTypingIndicator.d.ts +2 -0
  96. package/ui/ChatTypingIndicator.js +30 -0
  97. package/ui/ChatTypingIndicator.js.map +1 -0
  98. package/ui/ChatWindow.d.ts +21 -0
  99. package/ui/ChatWindow.js +108 -0
  100. package/ui/ChatWindow.js.map +1 -0
  101. package/ui/ChoiceExpander.js +1 -1
  102. package/ui/ChoiceExpander.js.map +1 -1
  103. package/ui/Dropdown.d.ts +20 -3
  104. package/ui/Dropdown.js +57 -23
  105. package/ui/Dropdown.js.map +1 -1
  106. package/ui/ElasticHeight.d.ts +0 -1
  107. package/ui/ElasticHeight.js +14 -23
  108. package/ui/ElasticHeight.js.map +1 -1
  109. package/ui/Loader.d.ts +5 -4
  110. package/ui/Loader.js +11 -10
  111. package/ui/Loader.js.map +1 -1
  112. package/ui/Popin.js +2 -2
  113. package/ui/Popin.js.map +1 -1
  114. package/ui/Scrollbar.d.ts +14 -0
  115. package/ui/Scrollbar.js +68 -0
  116. package/ui/Scrollbar.js.map +1 -0
  117. package/ui/SidebarLayout.d.ts +3 -1
  118. package/ui/SidebarLayout.js +32 -24
  119. package/ui/SidebarLayout.js.map +1 -1
  120. package/ui/Tooltip.d.ts +8 -0
  121. package/ui/Tooltip.js +2 -0
  122. package/ui/arrows/Arrows.d.ts +1 -0
  123. package/ui/arrows/Arrows.js +19 -17
  124. package/ui/arrows/Arrows.js.map +1 -1
  125. package/ui/buttons/Button.type.d.ts +1 -1
  126. package/ui/buttons/Button.type.js.map +1 -1
  127. package/ui/carousel/Carousel.context.d.ts +27 -0
  128. package/ui/carousel/Carousel.context.js +2 -0
  129. package/ui/carousel/Carousel.d.ts +3 -0
  130. package/ui/carousel/Carousel.js +12 -0
  131. package/ui/carousel/Carousel.js.map +1 -0
  132. package/ui/carousel/CarouselBody.d.ts +6 -0
  133. package/ui/carousel/CarouselBody.js +21 -0
  134. package/ui/carousel/CarouselBody.js.map +1 -0
  135. package/ui/carousel/CarouselItem.d.ts +6 -0
  136. package/ui/carousel/CarouselItem.js +21 -0
  137. package/ui/carousel/CarouselItem.js.map +1 -0
  138. package/ui/carousel/CarouselNext.d.ts +8 -0
  139. package/ui/carousel/CarouselNext.js +23 -0
  140. package/ui/carousel/CarouselNext.js.map +1 -0
  141. package/ui/carousel/CarouselPrevious.d.ts +8 -0
  142. package/ui/carousel/CarouselPrevious.js +23 -0
  143. package/ui/carousel/CarouselPrevious.js.map +1 -0
  144. package/ui/contexts/TridentUIConfig.js +1 -1
  145. package/ui/forms/CheckboxSelect.d.ts +31 -0
  146. package/ui/forms/CheckboxSelect.js +119 -0
  147. package/ui/forms/CheckboxSelect.js.map +1 -0
  148. package/ui/forms/Filter.d.ts +8 -4
  149. package/ui/forms/Filter.js +23 -45
  150. package/ui/forms/Filter.js.map +1 -1
  151. package/ui/forms/FormControl.js +6 -6
  152. package/ui/forms/NumberField.d.ts +10 -10
  153. package/ui/forms/NumberField.js +8 -8
  154. package/ui/forms/PhoneField.d.ts +5 -10
  155. package/ui/forms/PhoneField.js +29 -211
  156. package/ui/forms/PhoneField.js.map +1 -1
  157. package/ui/forms/PhoneFieldFullInput.d.ts +16 -0
  158. package/ui/forms/PhoneFieldFullInput.js +116 -0
  159. package/ui/forms/PhoneFieldFullInput.js.map +1 -0
  160. package/ui/forms/PhoneFieldSplitInput.d.ts +19 -0
  161. package/ui/forms/PhoneFieldSplitInput.js +159 -0
  162. package/ui/forms/PhoneFieldSplitInput.js.map +1 -0
  163. package/ui/forms/Select.js +4 -4
  164. package/ui/forms/Switch.d.ts +3 -3
  165. package/ui/forms/Switch.js +51 -34
  166. package/ui/forms/Switch.js.map +1 -1
  167. package/ui/forms/TextField.js +4 -4
  168. package/ui/forms/TextField.js.map +1 -1
  169. package/ui/forms/checkboxes/Checkbox.d.ts +10 -12
  170. package/ui/forms/checkboxes/Checkbox.js +38 -55
  171. package/ui/forms/checkboxes/Checkbox.js.map +1 -1
  172. package/ui/forms/checkboxes/Checkboxes.js +2 -2
  173. package/ui/forms/checkboxes/Checkboxes.js.map +1 -1
  174. package/ui/forms/password/Password.js +4 -4
  175. package/ui/frame/Frame.d.ts +8 -0
  176. package/ui/frame/Frame.js +16 -0
  177. package/ui/frame/Frame.js.map +1 -0
  178. package/ui/frame/FrameLabelsWrapper.d.ts +5 -0
  179. package/ui/frame/FrameLabelsWrapper.js +12 -0
  180. package/ui/frame/FrameLabelsWrapper.js.map +1 -0
  181. package/ui/frame/FrameTitle.d.ts +7 -0
  182. package/ui/frame/FrameTitle.js +25 -0
  183. package/ui/frame/FrameTitle.js.map +1 -0
  184. package/ui/frame/FrameWrapper.d.ts +6 -0
  185. package/ui/frame/FrameWrapper.js +14 -0
  186. package/ui/frame/FrameWrapper.js.map +1 -0
  187. package/ui/frame/SliderFrame.d.ts +14 -0
  188. package/ui/frame/SliderFrame.js +50 -0
  189. package/ui/frame/SliderFrame.js.map +1 -0
  190. package/ui/helpers/colors/colors.d.ts +4 -0
  191. package/ui/helpers/colors/colors.js +6 -1
  192. package/ui/helpers/colors/colors.js.map +1 -1
  193. package/ui/helpers/phone/defaultPrefixes.js +28 -28
  194. package/ui/helpers/phone/defaultPrefixes.js.map +1 -1
  195. package/ui/helpers/phone/formatters.d.ts +11 -0
  196. package/ui/helpers/phone/formatters.js +32 -1
  197. package/ui/helpers/phone/formatters.js.map +1 -1
  198. package/ui/helpers/phone/index.d.ts +1 -1
  199. package/ui/helpers/phone/index.js +3 -3
  200. package/ui/hooks/useValue.js +1 -1
  201. package/ui/hooks/useValue.js.map +1 -1
  202. package/ui/tabs/Tabs.js +1 -1
  203. package/ui/tabs/Tabs.js.map +1 -1
  204. package/ui/Breadcrumb.themes.d.ts +0 -8
  205. package/ui/Breadcrumb.themes.js +0 -16
  206. package/ui/Breadcrumb.themes.js.map +0 -1
@@ -1,8 +1,7 @@
1
1
  @layer utilities {
2
2
  /* This file is for styling the controls of the form inputs (checkbox, radio, switch, filter) */
3
3
  /* Styling the controls by their HTML semantic allows us to visually guarantee the non-regression of this semantic */
4
- /* Radio and Checkbox */
5
- label > span > input[type='checkbox']:not([role='switch']),
4
+ /* Radio */
6
5
  label > span > input[type='radio'] {
7
6
  opacity: 0;
8
7
  position: absolute;
@@ -10,7 +9,6 @@
10
9
  height: 100%;
11
10
  border: 0;
12
11
  }
13
- label > span > input[type='checkbox']:not([role='switch']) + span,
14
12
  label > span > input[type='radio'] + span {
15
13
  @apply border transition-all duration-200;
16
14
  --tw-ring-color: transparent;
@@ -20,25 +18,20 @@
20
18
  align-items: center;
21
19
  justify-content: center;
22
20
  }
23
- label > span > input[type='checkbox']:not([role='switch']) + span svg,
24
21
  label > span > input[type='radio'] + span svg {
25
22
  opacity: 0;
26
23
  transform: scale(0);
27
24
  transform-origin: center;
28
25
  transition: all var(--transition-duration-boop) var(--transition-fn-boop);
29
26
  }
30
- label > span > input[type='checkbox']:not([role='switch']):checked + span svg,
31
27
  label > span > input[type='radio']:checked + span svg {
32
28
  opacity: 1;
33
29
  transform: scale(1);
34
30
  }
35
- label > span > input[type='checkbox']:not([role='switch']):checked + span,
36
- label > span > input[type='checkbox']:not([role='switch']):not([disabled]):hover + span,
37
31
  label > span > input[type='radio']:checked + span,
38
32
  label > span > input[type='radio']:not([disabled]):hover + span {
39
33
  @apply border-black;
40
34
  }
41
- label > span > input[type='checkbox']:not([role='switch']):focus-visible + span,
42
35
  label > span > input[type='radio']:focus-visible + span {
43
36
  @apply ring-8;
44
37
  --tw-ring-color: color-mix(in oklab, var(--color-lavender) 20%, transparent);
@@ -46,9 +39,6 @@
46
39
  label > span > input[type='radio'] + span {
47
40
  @apply rounded-full;
48
41
  }
49
- label > span > input[type='checkbox']:not([role='switch']) + span {
50
- border-radius: calc(var(--spacing) * 8);
51
- }
52
42
  /* Filter */
53
43
  @media (hover: hover) and (pointer: fine) {
54
44
  label:active > input[type='checkbox'][data-name='Filter']:not(:disabled) {
@@ -100,62 +90,21 @@
100
90
  --tw-ring-color: color-mix(in oklab, var(--color-lavender) 20%, transparent);
101
91
  }
102
92
  /* Switch */
103
- label > span > input[type='checkbox'][role='switch'] + span {
104
- @apply transition-all;
93
+ input[role='switch'][data-name='Switch'] + span {
105
94
  @apply relative flex items-center transition-colors duration-200;
106
95
  @apply ring-0;
107
96
  --tw-ring-color: color-mix(in oklab, var(--color-lavender) 0%, transparent);
108
- background-color: var(--color-middleGrey);
109
- border-radius: var(--radius-pill);
110
- }
111
- label > span > input[type='checkbox'][role='switch'] + span > svg {
112
- transition: all var(--transition-duration-boop) var(--transition-fn-boop);
113
- transform: translate(calc(0% + 4px));
114
- }
115
- label > span > input[type='checkbox'][role='switch'] + span > svg circle + circle {
116
- opacity: 1;
117
- transition: opacity var(--transition-duration-boop) var(--transition-fn-boop);
118
- }
119
- label > span > input[type='checkbox'][role='switch'] + span > svg path {
120
- opacity: 0;
121
- scale: 0;
122
- transform-origin: center;
123
- transition:
124
- opacity var(--transition-duration-boop) var(--transition-fn-boop),
125
- scale var(--transition-duration-boop) var(--transition-fn-boop);
126
- }
127
- label > span > input[type='checkbox'][role='switch']:checked + span {
128
- background-color: var(--color-saffron);
129
- }
130
- label > span > input[type='checkbox'][role='switch']:checked + span > svg {
131
- transform: translate(calc(100% + 4px));
132
- }
133
- label > span > input[type='checkbox'][role='switch']:checked + span > svg circle + circle {
134
- opacity: 0;
135
- }
136
- label > span > input[type='checkbox'][role='switch']:checked + span > svg path {
137
- scale: 1;
138
- opacity: 1;
139
- }
140
- label > span > input[type='checkbox'][role='switch']:focus-visible + span {
141
- @apply ring-8;
142
- --tw-ring-color: color-mix(in oklab, var(--color-lavender) 20%, transparent);
143
97
  }
144
98
 
145
- button[role='switch'][data-name='Switch'] {
146
- @apply relative flex items-center transition-colors duration-200;
147
- @apply ring-0;
148
- --tw-ring-color: color-mix(in oklab, var(--color-lavender) 0%, transparent);
149
- }
150
- button[role='switch'][data-name='Switch'] svg {
99
+ input[role='switch'][data-name='Switch'] + span svg {
151
100
  transition: all var(--transition-duration-boop) var(--transition-fn-boop);
152
101
  transform: translate(calc(0%));
153
102
  }
154
- button[role='switch'][data-name='Switch'] svg circle + circle {
103
+ input[role='switch'][data-name='Switch'] + span svg circle + circle {
155
104
  opacity: 1;
156
105
  transition: opacity var(--transition-duration-boop) var(--transition-fn-boop);
157
106
  }
158
- button[role='switch'][data-name='Switch'] svg path {
107
+ input[role='switch'][data-name='Switch'] + span svg path {
159
108
  opacity: 0;
160
109
  scale: 0;
161
110
  transform-origin: center;
@@ -163,20 +112,17 @@
163
112
  opacity var(--transition-duration-boop) var(--transition-fn-boop),
164
113
  scale var(--transition-duration-boop) var(--transition-fn-boop);
165
114
  }
166
- button[role='switch'][data-name='Switch'][aria-checked='true'] {
167
- background-color: var(--color-saffron);
168
- }
169
- button[role='switch'][data-name='Switch'][aria-checked='true'] svg {
115
+ input[role='switch'][data-name='Switch']:checked + span svg {
170
116
  transform: translate(calc(100%));
171
117
  }
172
- button[role='switch'][data-name='Switch'][aria-checked='true'] svg circle + circle {
118
+ input[role='switch'][data-name='Switch']:checked + span svg circle + circle {
173
119
  opacity: 0;
174
120
  }
175
- button[role='switch'][data-name='Switch'][aria-checked='true'] svg path {
121
+ input[role='switch'][data-name='Switch']:checked + span svg path {
176
122
  scale: 1;
177
123
  opacity: 1;
178
124
  }
179
- button[role='switch'][data-name='Switch']:focus-visible {
125
+ input[role='switch'][data-name='Switch']:focus-visible + span {
180
126
  @apply ring-8;
181
127
  --tw-ring-color: color-mix(in oklab, var(--color-lavender) 20%, transparent);
182
128
  }
@@ -159,7 +159,7 @@
159
159
  color: hsl(0deg 0% 0%);
160
160
  font-size: 0.75rem;
161
161
  line-height: 0.875rem;
162
- @apply font-semibold;
162
+ font-weight: 600;
163
163
 
164
164
  left: calc(0.5 * var(--thumbWidth));
165
165
  }
@@ -10,5 +10,3 @@
10
10
  }
11
11
 
12
12
  @custom-variant hoverable (@media (hover: hover) and (pointer: fine));
13
-
14
- @custom-variant popover ('open', '&:popover-open');
@@ -1,15 +1,15 @@
1
1
  "use client";
2
2
  import { t as e } from "../chunks/clsx.js";
3
- import t from "./hooks/useResizeObserver.js";
4
- import { ElasticHeight as n } from "./ElasticHeight.js";
5
- import { Colors as r, getBgColor as i, getBorderColor as a, getTextColor as o } from "./helpers/colors/colors.js";
6
- import { useCountdown as s } from "./hooks/useCountdown.js";
3
+ import { ElasticHeight as t } from "./ElasticHeight.js";
4
+ import { Colors as n, getBgColor as r, getBorderColor as i, getTextColor as a } from "./helpers/colors/colors.js";
5
+ import { useCountdown as o } from "./hooks/useCountdown.js";
6
+ import s from "./hooks/useResizeObserver.js";
7
7
  import { useEffect as c, useId as l, useRef as u, useState as d } from "react";
8
8
  import { Icon as f } from "@clubmed/trident-icons";
9
9
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
10
10
  //#region lib/ui/AdvancedToast.tsx
11
- var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, children: x, accentColor: S = r.orange, duration: C = 1e4, onClose: w, toastId: T, updateHeight: E, ...D }) => {
12
- let O = l(), [k, A] = d(!1), [j, M] = d(!1), N = u(null), { progress: P } = s({
11
+ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, children: x, accentColor: S = n.orange, duration: C = 1e4, onClose: w, toastId: T, updateHeight: E, ...D }) => {
12
+ let O = l(), [k, A] = d(!1), [j, M] = d(!1), N = u(null), { progress: P } = o({
13
13
  duration: C,
14
14
  isPaused: j,
15
15
  isVisible: y
@@ -18,7 +18,7 @@ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, ch
18
18
  P === 100 && w?.();
19
19
  }, [P, w]);
20
20
  let F = () => M(!0), I = () => M(!1), L = () => M(!1);
21
- return t({
21
+ return s({
22
22
  ref: N,
23
23
  onResize: () => {
24
24
  N.current && E(T, N.current.offsetHeight);
@@ -26,7 +26,7 @@ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, ch
26
26
  }), /* @__PURE__ */ m("div", {
27
27
  ref: N,
28
28
  ...D,
29
- className: e(y ? "animate-slideRightEnter" : "animate-slideRightExit opacity-0", "relative isolate flex gap-x-20 rounded-16 bg-white p-20 text-black transition-opacity duration-300 border-1 overflow-hidden", a(S), h),
29
+ className: e(y ? "animate-slide-right-enter" : "animate-slide-right-exit opacity-0", "relative isolate flex gap-x-20 rounded-16 bg-white p-20 text-black transition-opacity duration-300 border-1 overflow-hidden", i(S), h),
30
30
  role: "note",
31
31
  onMouseDown: F,
32
32
  onMouseUp: I,
@@ -35,7 +35,7 @@ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, ch
35
35
  /* @__PURE__ */ p(f, {
36
36
  name: v,
37
37
  width: "30px",
38
- className: e("flex-shrink-0 pt-4", o(S))
38
+ className: e("flex-shrink-0 pt-4", a(S))
39
39
  }),
40
40
  /* @__PURE__ */ m("div", {
41
41
  className: "flex flex-1 flex-col gap-12 pe-24 text-b4",
@@ -54,7 +54,7 @@ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, ch
54
54
  style: { rotate: k ? "180deg" : "0deg" },
55
55
  className: "transition-all duration-300"
56
56
  })]
57
- }), /* @__PURE__ */ p(n, {
57
+ }), /* @__PURE__ */ p(t, {
58
58
  isExpanded: k,
59
59
  children: /* @__PURE__ */ p("div", {
60
60
  className: "pt-4",
@@ -76,7 +76,7 @@ var h = ({ className: h, title: g, body: _, icon: v, isVisible: y, labels: b, ch
76
76
  C !== !1 && /* @__PURE__ */ p("div", {
77
77
  className: "absolute bottom-0 left-0 right-0 h-4 overflow-hidden rounded-b-16",
78
78
  children: /* @__PURE__ */ p("div", {
79
- className: i(S),
79
+ className: r(S),
80
80
  style: {
81
81
  width: "100%",
82
82
  height: "100%",
@@ -1 +1 @@
1
- {"version":3,"file":"AdvancedToast.js","names":[],"sources":["../../lib/ui/AdvancedToast.tsx"],"sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type FunctionComponent,\n} from 'react';\n\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\nimport { ElasticHeight } from './ElasticHeight';\nimport { Colors, getBgColor, getBorderColor, getTextColor } from './helpers/colors/colors';\nimport { useCountdown } from './hooks/useCountdown';\nimport useResizeObserver from './hooks/useResizeObserver';\n\ninterface Props extends ComponentPropsWithoutRef<'div'> {\n title: string;\n body: string;\n icon: IconicNames;\n isVisible: boolean;\n labels: {\n close: string;\n details: string;\n };\n onClose?: () => void;\n children?: React.ReactNode;\n accentColor?: Colors;\n moreInfoLabel?: string;\n moreInfoHref?: string;\n duration?: false | number;\n toastId: string;\n updateHeight: (id: string, height: number) => void;\n}\n\nexport const AdvancedToast: FunctionComponent<Props> = ({\n className,\n title,\n body,\n icon,\n isVisible,\n labels,\n children,\n accentColor = Colors.orange,\n duration = 10000,\n onClose,\n toastId,\n updateHeight,\n ...attrs\n}) => {\n const id = useId();\n const [isDetailsExpanded, setIsDetailsExpanded] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const toastRef = useRef<HTMLDivElement>(null!);\n\n const { progress } = useCountdown({ duration, isPaused, isVisible });\n useEffect(() => {\n if (progress === 100) {\n onClose?.();\n }\n }, [progress, onClose]);\n\n const handleMouseDown = () => setIsPaused(true);\n const handleMouseUp = () => setIsPaused(false);\n const handleMouseLeave = () => setIsPaused(false);\n\n useResizeObserver<HTMLDivElement>({\n ref: toastRef,\n onResize: () => {\n if (toastRef.current) {\n updateHeight(toastId, toastRef.current.offsetHeight);\n }\n },\n });\n\n return (\n <div\n ref={toastRef}\n {...attrs}\n className={clsx(\n isVisible ? 'animate-slideRightEnter' : 'animate-slideRightExit opacity-0',\n 'relative isolate flex gap-x-20 rounded-16 bg-white p-20 text-black transition-opacity duration-300 border-1 overflow-hidden',\n getBorderColor(accentColor),\n className,\n )}\n role=\"note\"\n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseLeave}\n >\n <Icon\n name={icon}\n width=\"30px\"\n className={clsx('flex-shrink-0 pt-4', getTextColor(accentColor))}\n />\n <div className=\"flex flex-1 flex-col gap-12 pe-24 text-b4\">\n <div>\n <p className=\" font-bold\" id={id}>\n {title}\n </p>\n <p>{body}</p>\n </div>\n\n {children && (\n <div>\n <button\n onClick={() => setIsDetailsExpanded(!isDetailsExpanded)}\n aria-expanded={isDetailsExpanded}\n className=\"flex w-fit items-center gap-8 text-b5 font-normal\"\n type=\"button\"\n >\n <span>{labels.details}</span>\n <Icon\n name=\"ArrowDefaultDown\"\n width=\"24px\"\n style={{ rotate: isDetailsExpanded ? '180deg' : '0deg' }}\n className=\"transition-all duration-300\"\n />\n </button>\n <ElasticHeight isExpanded={isDetailsExpanded}>\n <div className=\"pt-4\">{children}</div>\n </ElasticHeight>\n </div>\n )}\n </div>\n\n {onClose && (\n <button\n aria-describedby={id}\n aria-label={labels.close}\n className=\"absolute end-0 top-0 mt-20 me-13 text-black\"\n onClick={onClose}\n type=\"button\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n\n {duration !== false && (\n <div className=\"absolute bottom-0 left-0 right-0 h-4 overflow-hidden rounded-b-16\">\n <div\n className={getBgColor(accentColor)}\n style={{\n width: '100%',\n height: '100%',\n transform: `scaleX(${(100 - progress) / 100})`,\n transformOrigin: 'left',\n transition: 'transform 16ms linear',\n }}\n />\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AAqCA,IAAa,KAA2C,EACtD,cACA,UACA,SACA,SACA,cACA,WACA,aACA,iBAAc,EAAO,QACrB,cAAW,KACX,YACA,YACA,iBACA,GAAG,QACC;CACJ,IAAM,IAAK,GAAO,EACZ,CAAC,GAAmB,KAAwB,EAAS,GAAM,EAC3D,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,IAAW,EAAuB,KAAM,EAExC,EAAE,gBAAa,EAAa;EAAE;EAAU;EAAU;EAAW,CAAC;AACpE,SAAgB;AACd,EAAI,MAAa,OACf,KAAW;IAEZ,CAAC,GAAU,EAAQ,CAAC;CAEvB,IAAM,UAAwB,EAAY,GAAK,EACzC,UAAsB,EAAY,GAAM,EACxC,UAAyB,EAAY,GAAM;AAWjD,QATA,EAAkC;EAChC,KAAK;EACL,gBAAgB;AACd,GAAI,EAAS,WACX,EAAa,GAAS,EAAS,QAAQ,aAAa;;EAGzD,CAAC,EAGA,kBAAC,OAAD;EACE,KAAK;EACL,GAAI;EACJ,WAAW,EACT,IAAY,4BAA4B,oCACxC,+HACA,EAAe,EAAY,EAC3B,EACD;EACD,MAAK;EACL,aAAa;EACb,WAAW;EACX,cAAc;YAZhB;GAcE,kBAAC,GAAD;IACE,MAAM;IACN,OAAM;IACN,WAAW,EAAK,sBAAsB,EAAa,EAAY,CAAA;IAC/D,CAAA;GACF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;KAAiB;eAC3B;KACC,CAAA,EACJ,kBAAC,KAAD,EAAA,UAAI,GAAS,CAAA,CACT,EAAA,CAAA,EAEL,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,UAAD;KACE,eAAe,EAAqB,CAAC,EAAkB;KACvD,iBAAe;KACf,WAAU;KACV,MAAK;eAJP,CAME,kBAAC,QAAD,EAAA,UAAO,EAAO,SAAe,CAAA,EAC7B,kBAAC,GAAD;MACE,MAAK;MACL,OAAM;MACN,OAAO,EAAE,QAAQ,IAAoB,WAAW,QAAQ;MACxD,WAAU;MACV,CAAA,CAAA;QAEJ,kBAAC,GAAD;KAAe,YAAY;eACzB,kBAAC,OAAD;MAAK,WAAU;MAAQ;MAAe,CAAA;KACxB,CAAA,CACZ,EAAA,CAAA,CAAA;;GAIT,KACC,kBAAC,UAAD;IACE,oBAAkB;IAClB,cAAY,EAAO;IACnB,WAAU;IACV,SAAS;IACT,MAAK;cAEL,kBAAC,GAAD;KAAM,MAAK;KAAe,OAAM;KAAS,CAAA;IAClC,CAAA;GAGV,MAAa,MACZ,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KACE,WAAW,EAAW,EAAY;KAClC,OAAO;MACL,OAAO;MACP,QAAQ;MACR,WAAW,WAAW,MAAM,KAAY,IAAI;MAC5C,iBAAiB;MACjB,YAAY;;KAEd,CAAA;IACE,CAAA"}
1
+ {"version":3,"file":"AdvancedToast.js","names":[],"sources":["../../lib/ui/AdvancedToast.tsx"],"sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type FunctionComponent,\n} from 'react';\n\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\nimport { ElasticHeight } from './ElasticHeight';\nimport { Colors, getBgColor, getBorderColor, getTextColor } from './helpers/colors/colors';\nimport { useCountdown } from './hooks/useCountdown';\nimport useResizeObserver from './hooks/useResizeObserver';\n\ninterface Props extends ComponentPropsWithoutRef<'div'> {\n title: string;\n body: string;\n icon: IconicNames;\n isVisible: boolean;\n labels: {\n close: string;\n details: string;\n };\n onClose?: () => void;\n children?: React.ReactNode;\n accentColor?: Colors;\n moreInfoLabel?: string;\n moreInfoHref?: string;\n duration?: false | number;\n toastId: string;\n updateHeight: (id: string, height: number) => void;\n}\n\nexport const AdvancedToast: FunctionComponent<Props> = ({\n className,\n title,\n body,\n icon,\n isVisible,\n labels,\n children,\n accentColor = Colors.orange,\n duration = 10000,\n onClose,\n toastId,\n updateHeight,\n ...attrs\n}) => {\n const id = useId();\n const [isDetailsExpanded, setIsDetailsExpanded] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const toastRef = useRef<HTMLDivElement>(null!);\n\n const { progress } = useCountdown({ duration, isPaused, isVisible });\n useEffect(() => {\n if (progress === 100) {\n onClose?.();\n }\n }, [progress, onClose]);\n\n const handleMouseDown = () => setIsPaused(true);\n const handleMouseUp = () => setIsPaused(false);\n const handleMouseLeave = () => setIsPaused(false);\n\n useResizeObserver<HTMLDivElement>({\n ref: toastRef,\n onResize: () => {\n if (toastRef.current) {\n updateHeight(toastId, toastRef.current.offsetHeight);\n }\n },\n });\n\n return (\n <div\n ref={toastRef}\n {...attrs}\n className={clsx(\n isVisible ? 'animate-slide-right-enter' : 'animate-slide-right-exit opacity-0',\n 'relative isolate flex gap-x-20 rounded-16 bg-white p-20 text-black transition-opacity duration-300 border-1 overflow-hidden',\n getBorderColor(accentColor),\n className,\n )}\n role=\"note\"\n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseLeave}\n >\n <Icon\n name={icon}\n width=\"30px\"\n className={clsx('flex-shrink-0 pt-4', getTextColor(accentColor))}\n />\n <div className=\"flex flex-1 flex-col gap-12 pe-24 text-b4\">\n <div>\n <p className=\" font-bold\" id={id}>\n {title}\n </p>\n <p>{body}</p>\n </div>\n\n {children && (\n <div>\n <button\n onClick={() => setIsDetailsExpanded(!isDetailsExpanded)}\n aria-expanded={isDetailsExpanded}\n className=\"flex w-fit items-center gap-8 text-b5 font-normal\"\n type=\"button\"\n >\n <span>{labels.details}</span>\n <Icon\n name=\"ArrowDefaultDown\"\n width=\"24px\"\n style={{ rotate: isDetailsExpanded ? '180deg' : '0deg' }}\n className=\"transition-all duration-300\"\n />\n </button>\n <ElasticHeight isExpanded={isDetailsExpanded}>\n <div className=\"pt-4\">{children}</div>\n </ElasticHeight>\n </div>\n )}\n </div>\n\n {onClose && (\n <button\n aria-describedby={id}\n aria-label={labels.close}\n className=\"absolute end-0 top-0 mt-20 me-13 text-black\"\n onClick={onClose}\n type=\"button\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n\n {duration !== false && (\n <div className=\"absolute bottom-0 left-0 right-0 h-4 overflow-hidden rounded-b-16\">\n <div\n className={getBgColor(accentColor)}\n style={{\n width: '100%',\n height: '100%',\n transform: `scaleX(${(100 - progress) / 100})`,\n transformOrigin: 'left',\n transition: 'transform 16ms linear',\n }}\n />\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AAqCA,IAAa,KAA2C,EACtD,cACA,UACA,SACA,SACA,cACA,WACA,aACA,iBAAc,EAAO,QACrB,cAAW,KACX,YACA,YACA,iBACA,GAAG,QACC;CACJ,IAAM,IAAK,GAAO,EACZ,CAAC,GAAmB,KAAwB,EAAS,GAAM,EAC3D,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,IAAW,EAAuB,KAAM,EAExC,EAAE,gBAAa,EAAa;EAAE;EAAU;EAAU;EAAW,CAAC;AACpE,SAAgB;AACd,EAAI,MAAa,OACf,KAAW;IAEZ,CAAC,GAAU,EAAQ,CAAC;CAEvB,IAAM,UAAwB,EAAY,GAAK,EACzC,UAAsB,EAAY,GAAM,EACxC,UAAyB,EAAY,GAAM;AAWjD,QATA,EAAkC;EAChC,KAAK;EACL,gBAAgB;AACd,GAAI,EAAS,WACX,EAAa,GAAS,EAAS,QAAQ,aAAa;;EAGzD,CAAC,EAGA,kBAAC,OAAD;EACE,KAAK;EACL,GAAI;EACJ,WAAW,EACT,IAAY,8BAA8B,sCAC1C,+HACA,EAAe,EAAY,EAC3B,EACD;EACD,MAAK;EACL,aAAa;EACb,WAAW;EACX,cAAc;YAZhB;GAcE,kBAAC,GAAD;IACE,MAAM;IACN,OAAM;IACN,WAAW,EAAK,sBAAsB,EAAa,EAAY,CAAA;IAC/D,CAAA;GACF,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;KAAG,WAAU;KAAiB;eAC3B;KACC,CAAA,EACJ,kBAAC,KAAD,EAAA,UAAI,GAAS,CAAA,CACT,EAAA,CAAA,EAEL,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,UAAD;KACE,eAAe,EAAqB,CAAC,EAAkB;KACvD,iBAAe;KACf,WAAU;KACV,MAAK;eAJP,CAME,kBAAC,QAAD,EAAA,UAAO,EAAO,SAAe,CAAA,EAC7B,kBAAC,GAAD;MACE,MAAK;MACL,OAAM;MACN,OAAO,EAAE,QAAQ,IAAoB,WAAW,QAAQ;MACxD,WAAU;MACV,CAAA,CAAA;QAEJ,kBAAC,GAAD;KAAe,YAAY;eACzB,kBAAC,OAAD;MAAK,WAAU;MAAQ;MAAe,CAAA;KACxB,CAAA,CACZ,EAAA,CAAA,CAAA;;GAIT,KACC,kBAAC,UAAD;IACE,oBAAkB;IAClB,cAAY,EAAO;IACnB,WAAU;IACV,SAAS;IACT,MAAK;cAEL,kBAAC,GAAD;KAAM,MAAK;KAAe,OAAM;KAAS,CAAA;IAClC,CAAA;GAGV,MAAa,MACZ,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KACE,WAAW,EAAW,EAAY;KAClC,OAAO;MACL,OAAO;MACP,QAAQ;MACR,WAAW,WAAW,MAAM,KAAY,IAAI;MAC5C,iBAAiB;MACjB,YAAY;;KAEd,CAAA;IACE,CAAA"}
package/ui/BasicToast.js CHANGED
@@ -10,7 +10,7 @@ function l({ className: l, description: u, href: d, icon: f, incentive: p, isVis
10
10
  let S = r(v), C = a(), w = b ?? u;
11
11
  return /* @__PURE__ */ c("div", {
12
12
  ...x,
13
- className: e(m ? "animate-slideRightEnter" : "animate-slideRightExit opacity-0", "relative isolate flex gap-x-20 rounded-16 p-20 transition-opacity duration-300", t(S), n(S), l),
13
+ className: e(m ? "animate-slide-right-enter" : "animate-slide-right-exit opacity-0", "relative isolate flex gap-x-20 rounded-16 p-20 transition-opacity duration-300", t(S), n(S), l),
14
14
  role: "note",
15
15
  children: [
16
16
  f && /* @__PURE__ */ s(o, {
@@ -1 +1 @@
1
- {"version":3,"file":"BasicToast.js","names":[],"sources":["../../lib/ui/BasicToast.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport { type ComponentPropsWithoutRef, type PropsWithChildren, useId } from 'react';\n\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\nimport { getBgColor, getComplementaryTextColor, getThemeColor } from './helpers/colors/colors';\nimport { Link } from './Link';\nimport type { Theme } from './types/Theme';\n\nexport interface BasicToastProps extends ComponentPropsWithoutRef<'div'> {\n /**\n * @deprecated use children slot instead\n */\n description?: string;\n href: string;\n icon?: IconicNames;\n incentive: string;\n isVisible: boolean;\n labels: { close: string };\n onClick?: () => void;\n onClose?: () => void;\n theme: Theme;\n title: string;\n}\n\nexport function BasicToast({\n className,\n description,\n href,\n icon,\n incentive,\n isVisible,\n labels,\n onClick,\n onClose,\n theme = 'dark',\n title,\n children,\n ...attrs\n}: PropsWithChildren<BasicToastProps>) {\n const color = getThemeColor(theme);\n const id = useId();\n const content = children ?? description;\n\n return (\n <div\n {...attrs}\n className={clsx(\n isVisible ? 'animate-slideRightEnter' : 'animate-slideRightExit opacity-0',\n 'relative isolate flex gap-x-20 rounded-16 p-20 transition-opacity duration-300',\n getBgColor(color),\n getComplementaryTextColor(color),\n className,\n )}\n role=\"note\"\n >\n {icon && <Icon name={icon} width=\"30px\" />}\n <a className=\"group pe-44\" href={href} onClick={onClick}>\n <p className=\"mb-4 text-b3 font-bold\" id={id}>\n {title}\n </p>\n {content && <div className=\"mb-12 text-b4\">{content}</div>}\n <Link component=\"span\" className=\"text-b3 font-bold\" label={incentive} />\n </a>\n {onClose && (\n <button\n aria-describedby={id}\n aria-label={labels.close}\n className={clsx('absolute end-0 top-0 m-20', getComplementaryTextColor(color))}\n onClick={onClose}\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAyBA,SAAgB,EAAW,EACzB,cACA,gBACA,SACA,SACA,cACA,cACA,WACA,YACA,YACA,WAAQ,QACR,UACA,aACA,GAAG,KACkC;CACrC,IAAM,IAAQ,EAAc,EAAM,EAC5B,IAAK,GAAO,EACZ,IAAU,KAAY;AAE5B,QACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EACT,IAAY,4BAA4B,oCACxC,kFACA,EAAW,EAAM,EACjB,EAA0B,EAAM,EAChC,EACD;EACD,MAAK;YATP;GAWG,KAAQ,kBAAC,GAAD;IAAM,MAAM;IAAM,OAAM;IAAS,CAAA;GAC1C,kBAAC,KAAD;IAAG,WAAU;IAAoB;IAAe;cAAhD;KACE,kBAAC,KAAD;MAAG,WAAU;MAA6B;gBACvC;MACC,CAAA;KACH,KAAW,kBAAC,OAAD;MAAK,WAAU;gBAAiB;MAAc,CAAA;KAC1D,kBAAC,GAAD;MAAM,WAAU;MAAO,WAAU;MAAoB,OAAO;MAAa,CAAA;;;GAE1E,KACC,kBAAC,UAAD;IACE,oBAAkB;IAClB,cAAY,EAAO;IACnB,WAAW,EAAK,6BAA6B,EAA0B,EAAM,CAAC;IAC9E,SAAS;cAET,kBAAC,GAAD;KAAM,MAAK;KAAe,OAAM;KAAS,CAAA;IAClC,CAAA"}
1
+ {"version":3,"file":"BasicToast.js","names":[],"sources":["../../lib/ui/BasicToast.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport { type ComponentPropsWithoutRef, type PropsWithChildren, useId } from 'react';\n\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\nimport { getBgColor, getComplementaryTextColor, getThemeColor } from './helpers/colors/colors';\nimport { Link } from './Link';\nimport type { Theme } from './types/Theme';\n\nexport interface BasicToastProps extends ComponentPropsWithoutRef<'div'> {\n /**\n * @deprecated use children slot instead\n */\n description?: string;\n href: string;\n icon?: IconicNames;\n incentive: string;\n isVisible: boolean;\n labels: { close: string };\n onClick?: () => void;\n onClose?: () => void;\n theme: Theme;\n title: string;\n}\n\nexport function BasicToast({\n className,\n description,\n href,\n icon,\n incentive,\n isVisible,\n labels,\n onClick,\n onClose,\n theme = 'dark',\n title,\n children,\n ...attrs\n}: PropsWithChildren<BasicToastProps>) {\n const color = getThemeColor(theme);\n const id = useId();\n const content = children ?? description;\n\n return (\n <div\n {...attrs}\n className={clsx(\n isVisible ? 'animate-slide-right-enter' : 'animate-slide-right-exit opacity-0',\n 'relative isolate flex gap-x-20 rounded-16 p-20 transition-opacity duration-300',\n getBgColor(color),\n getComplementaryTextColor(color),\n className,\n )}\n role=\"note\"\n >\n {icon && <Icon name={icon} width=\"30px\" />}\n <a className=\"group pe-44\" href={href} onClick={onClick}>\n <p className=\"mb-4 text-b3 font-bold\" id={id}>\n {title}\n </p>\n {content && <div className=\"mb-12 text-b4\">{content}</div>}\n <Link component=\"span\" className=\"text-b3 font-bold\" label={incentive} />\n </a>\n {onClose && (\n <button\n aria-describedby={id}\n aria-label={labels.close}\n className={clsx('absolute end-0 top-0 m-20', getComplementaryTextColor(color))}\n onClick={onClose}\n >\n <Icon name=\"CrossDefault\" width=\"24px\" />\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAyBA,SAAgB,EAAW,EACzB,cACA,gBACA,SACA,SACA,cACA,cACA,WACA,YACA,YACA,WAAQ,QACR,UACA,aACA,GAAG,KACkC;CACrC,IAAM,IAAQ,EAAc,EAAM,EAC5B,IAAK,GAAO,EACZ,IAAU,KAAY;AAE5B,QACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EACT,IAAY,8BAA8B,sCAC1C,kFACA,EAAW,EAAM,EACjB,EAA0B,EAAM,EAChC,EACD;EACD,MAAK;YATP;GAWG,KAAQ,kBAAC,GAAD;IAAM,MAAM;IAAM,OAAM;IAAS,CAAA;GAC1C,kBAAC,KAAD;IAAG,WAAU;IAAoB;IAAe;cAAhD;KACE,kBAAC,KAAD;MAAG,WAAU;MAA6B;gBACvC;MACC,CAAA;KACH,KAAW,kBAAC,OAAD;MAAK,WAAU;gBAAiB;MAAc,CAAA;KAC1D,kBAAC,GAAD;MAAM,WAAU;MAAO,WAAU;MAAoB,OAAO;MAAa,CAAA;;;GAE1E,KACC,kBAAC,UAAD;IACE,oBAAkB;IAClB,cAAY,EAAO;IACnB,WAAW,EAAK,6BAA6B,EAA0B,EAAM,CAAC;IAC9E,SAAS;cAET,kBAAC,GAAD;KAAM,MAAK;KAAe,OAAM;KAAS,CAAA;IAClC,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import { ComponentPropsWithoutRef, FunctionComponent } from 'react';
2
2
  import { Theme } from './types/Theme';
3
3
  export interface BreadcrumbProps extends ComponentPropsWithoutRef<'nav'> {
4
- items: ({
4
+ items: Array<{
5
5
  href: string;
6
6
  label: string;
7
- } & ComponentPropsWithoutRef<'li'>)[];
7
+ }>;
8
8
  theme?: Theme;
9
9
  }
10
10
  export declare const Breadcrumb: FunctionComponent<BreadcrumbProps>;
package/ui/Breadcrumb.js CHANGED
@@ -1,43 +1,39 @@
1
1
  import { t as e } from "../chunks/clsx.js";
2
- import { getTheme as t } from "./Breadcrumb.themes.js";
3
- import { createElement as n } from "react";
4
- import { Icon as r } from "@clubmed/trident-icons";
5
- import { jsx as i } from "react/jsx-runtime";
2
+ import { getComplementaryTextColor as t, getThemeColor as n } from "./helpers/colors/colors.js";
3
+ import { createElement as r } from "react";
4
+ import { Icon as i } from "@clubmed/trident-icons";
5
+ import { jsx as a } from "react/jsx-runtime";
6
6
  //#region lib/ui/Breadcrumb.tsx
7
- var a = ({ className: a, items: o, theme: s = "light", ...c }) => {
8
- if (o.length == 0) return null;
9
- let [l, u, , ...d] = o, f = d.length ? d[d.length - 1] : o[o.length - 1], p = d.length ? [
10
- l,
11
- u,
7
+ var o = ({ className: o, items: s, theme: c = "light", ...l }) => {
8
+ if (s.length == 0) return null;
9
+ let u = t(n(c)), d = u === "text-white" ? u : "text-middleGrey", [f, p, , ...m] = s, h = m.length ? m[m.length - 1] : s[s.length - 1], g = m.length ? [
10
+ f,
11
+ p,
12
12
  {
13
- label: "",
14
- href: "",
15
- className: "breadcrumb-spacer"
13
+ label: "",
14
+ href: ""
16
15
  },
17
- f
18
- ] : o, { thStart: m, thEnd: h } = t(s);
19
- return /* @__PURE__ */ i("nav", {
20
- role: "navigation",
16
+ h
17
+ ] : s;
18
+ return /* @__PURE__ */ a("nav", {
21
19
  "aria-label": "Breadcrumb",
22
- ...c,
23
- className: e(a, "overflow-hidden"),
24
- "data-name": "Breadcrumb",
25
- children: /* @__PURE__ */ i("ol", {
26
- className: "scrollbar-hidden flex items-center overflow-x-auto font-sans text-b4",
27
- children: p.map(({ label: t, href: a, className: o, ...s }, c) => {
28
- let l = c === p.length - 1, u = a && !l;
29
- return /* @__PURE__ */ n("li", {
30
- ...s,
31
- ...l && { "aria-current": "page" },
32
- className: e("flex shrink-0 items-center", {
33
- [m]: !l,
34
- [h]: l
35
- }, o),
36
- key: `${t}-${c}`
37
- }, u ? /* @__PURE__ */ i("a", {
38
- href: a,
20
+ ...l,
21
+ className: e(o, "overflow-hidden"),
22
+ children: /* @__PURE__ */ a("ul", {
23
+ className: "scrollbar-hidden text-b4 flex items-center overflow-x-auto font-sans",
24
+ children: g.map(({ label: t, href: n }, o) => {
25
+ let s = o === g.length - 1, c = n && !s;
26
+ return /* @__PURE__ */ r("li", {
27
+ ...s && { "aria-current": "page" },
28
+ className: e("flex shrink-0 items-center", { [d]: !s }, {
29
+ "font-bold": s,
30
+ [u]: s
31
+ }),
32
+ key: t
33
+ }, c ? /* @__PURE__ */ a("a", {
34
+ href: n,
39
35
  children: t
40
- }) : t, !l && /* @__PURE__ */ i(r, {
36
+ }) : t, !s && /* @__PURE__ */ a(i, {
41
37
  className: "mx-4",
42
38
  name: "Diamond",
43
39
  width: "14px"
@@ -47,6 +43,6 @@ var a = ({ className: a, items: o, theme: s = "light", ...c }) => {
47
43
  });
48
44
  };
49
45
  //#endregion
50
- export { a as Breadcrumb };
46
+ export { o as Breadcrumb };
51
47
 
52
48
  //# sourceMappingURL=Breadcrumb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Breadcrumb.js","names":[],"sources":["../../lib/ui/Breadcrumb.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport type { ComponentPropsWithoutRef, FunctionComponent } from 'react';\n\nimport { getTheme } from './Breadcrumb.themes';\n\nimport type { Theme } from './types/Theme';\nimport { Icon } from '@clubmed/trident-icons';\n\nexport interface BreadcrumbProps extends ComponentPropsWithoutRef<'nav'> {\n items: ({\n href: string;\n label: string;\n } & ComponentPropsWithoutRef<'li'>)[];\n theme?: Theme;\n}\n\nexport const Breadcrumb: FunctionComponent<BreadcrumbProps> = ({\n className,\n items,\n theme = 'light',\n ...attrs\n}) => {\n if (items.length == 0) {\n return null;\n }\n\n const [first, second, , ...rest] = items;\n const lastItem = rest.length ? rest[rest.length - 1] : items[items.length - 1];\n const spacer = { label: '', href: '', className: 'breadcrumb-spacer' };\n const itemsToRender = !rest.length ? items : [first, second, spacer, lastItem];\n\n const { thStart, thEnd } = getTheme(theme);\n\n return (\n <nav\n role=\"navigation\"\n aria-label=\"Breadcrumb\"\n {...attrs}\n className={clsx(className, 'overflow-hidden')}\n data-name=\"Breadcrumb\"\n >\n <ol className=\"scrollbar-hidden flex items-center overflow-x-auto font-sans text-b4\">\n {itemsToRender.map(({ label, href, className, ...attrs }, index) => {\n const isLast = index === itemsToRender.length - 1;\n const isLink = href && !isLast;\n return (\n <li\n {...attrs}\n {...(isLast && { 'aria-current': 'page' })}\n className={clsx(\n 'flex shrink-0 items-center',\n {\n [thStart]: !isLast,\n [thEnd]: isLast,\n },\n className,\n )}\n key={`${label}-${index}`}\n >\n {isLink ? <a href={href}>{label}</a> : label}\n {!isLast && <Icon className=\"mx-4\" name=\"Diamond\" width=\"14px\" />}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":";;;;;;AAgBA,IAAa,KAAkD,EAC7D,cACA,UACA,WAAQ,SACR,GAAG,QACC;AACJ,KAAI,EAAM,UAAU,EAClB,QAAO;CAGT,IAAM,CAAC,GAAO,KAAU,GAAG,KAAQ,GAC7B,IAAW,EAAK,SAAS,EAAK,EAAK,SAAS,KAAK,EAAM,EAAM,SAAS,IAEtE,IAAiB,EAAK,SAAiB;EAAC;EAAO;EADtC;GAAE,OAAO;GAAI,MAAM;GAAI,WAAW;GAAqB;EACD;EAAS,GAAzC,GAE/B,EAAE,YAAS,aAAU,EAAS,EAAM;AAE1C,QACE,kBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,GAAI;EACJ,WAAW,EAAK,GAAW,kBAAkB;EAC7C,aAAU;YAEV,kBAAC,MAAD;GAAI,WAAU;aACX,EAAc,KAAK,EAAE,UAAO,SAAM,cAAW,GAAG,KAAS,MAAU;IAClE,IAAM,IAAS,MAAU,EAAc,SAAS,GAC1C,IAAS,KAAQ,CAAC;AACxB,WACE,kBAAC,MAAD;KACE,GAAI;KACJ,GAAK,KAAU,EAAE,gBAAgB,QAAQ;KACzC,WAAW,EACT,8BACA;OACG,IAAU,CAAC;OACX,IAAQ;MACV,EACD,EACD;KACD,KAAK,GAAG,EAAM,GAAG;KAId,EAFF,IAAS,kBAAC,KAAD;KAAS;eAAO;KAAU,CAAA,GAAG,GACtC,CAAC,KAAU,kBAAC,GAAD;KAAM,WAAU;KAAO,MAAK;KAAU,OAAM;KAAS,CAAA,CAC9D;KAEP;GACC,CAAA;EACD,CAAA"}
1
+ {"version":3,"file":"Breadcrumb.js","names":[],"sources":["../../lib/ui/Breadcrumb.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport type { ComponentPropsWithoutRef, FunctionComponent } from 'react';\n\nimport type { Theme } from './types/Theme';\nimport { Icon } from '@clubmed/trident-icons';\nimport { getComplementaryTextColor, getThemeColor } from './helpers/colors/colors';\n\nexport interface BreadcrumbProps extends ComponentPropsWithoutRef<'nav'> {\n items: Array<{\n href: string;\n label: string;\n }>;\n theme?: Theme;\n}\n\nexport const Breadcrumb: FunctionComponent<BreadcrumbProps> = ({\n className,\n items,\n theme = 'light',\n ...attrs\n}) => {\n if (items.length == 0) {\n return null;\n }\n\n const themeColor = getThemeColor(theme);\n const accentColor = getComplementaryTextColor(themeColor);\n const color = accentColor === 'text-white' ? accentColor : 'text-middleGrey';\n\n const [first, second, , ...rest] = items;\n const lastItem = rest.length ? rest[rest.length - 1] : items[items.length - 1];\n const spacer = { label: '', href: '' };\n const itemsToRender = !rest.length ? items : [first, second, spacer, lastItem];\n\n return (\n <nav aria-label=\"Breadcrumb\" {...attrs} className={clsx(className, 'overflow-hidden')}>\n <ul className=\"scrollbar-hidden text-b4 flex items-center overflow-x-auto font-sans\">\n {itemsToRender.map(({ label, href }, index) => {\n const isLast = index === itemsToRender.length - 1;\n const isLink = href && !isLast;\n\n return (\n <li\n {...(isLast && { 'aria-current': 'page' })}\n className={clsx(\n 'flex shrink-0 items-center',\n { [color]: !isLast },\n {\n 'font-bold': isLast,\n [accentColor]: isLast,\n },\n )}\n key={label}\n >\n {isLink ? <a href={href}>{label}</a> : label}\n {!isLast && <Icon className=\"mx-4\" name=\"Diamond\" width=\"14px\" />}\n </li>\n );\n })}\n </ul>\n </nav>\n );\n};\n"],"mappings":";;;;;;AAeA,IAAa,KAAkD,EAC7D,cACA,UACA,WAAQ,SACR,GAAG,QACC;AACJ,KAAI,EAAM,UAAU,EAClB,QAAO;CAIT,IAAM,IAAc,EADD,EAAc,EAAM,CACkB,EACnD,IAAQ,MAAgB,eAAe,IAAc,mBAErD,CAAC,GAAO,KAAU,GAAG,KAAQ,GAC7B,IAAW,EAAK,SAAS,EAAK,EAAK,SAAS,KAAK,EAAM,EAAM,SAAS,IAEtE,IAAiB,EAAK,SAAiB;EAAC;EAAO;EADtC;GAAE,OAAO;GAAK,MAAM;GAAI;EAC8B;EAAS,GAAzC;AAErC,QACE,kBAAC,OAAD;EAAK,cAAW;EAAa,GAAI;EAAO,WAAW,EAAK,GAAW,kBAAkB;YACnF,kBAAC,MAAD;GAAI,WAAU;aACX,EAAc,KAAK,EAAE,UAAO,WAAQ,MAAU;IAC7C,IAAM,IAAS,MAAU,EAAc,SAAS,GAC1C,IAAS,KAAQ,CAAC;AAExB,WACE,kBAAC,MAAD;KACE,GAAK,KAAU,EAAE,gBAAgB,QAAQ;KACzC,WAAW,EACT,8BACA,GAAG,IAAQ,CAAC,GAAQ,EACpB;MACE,aAAa;OACZ,IAAc;MAChB,CACF;KACD,KAAK;KAIF,EAFF,IAAS,kBAAC,KAAD;KAAS;eAAO;KAAU,CAAA,GAAG,GACtC,CAAC,KAAU,kBAAC,GAAD;KAAM,WAAU;KAAO,MAAK;KAAU,OAAM;KAAS,CAAA,CAC9D;KAEP;GACC,CAAA;EACD,CAAA"}
package/ui/ChatButton.js CHANGED
@@ -10,7 +10,7 @@ function o({ children: o = i, className: s, type: c = "button", "aria-label": l,
10
10
  "aria-label": m,
11
11
  tabIndex: u ?? 0,
12
12
  ...p,
13
- className: e("chat-button grid grid-cols-[24px_0fr] transition-[grid-template-columns] justify-center items-center overflow-hidden cursor-pointer transition-all rounded-pill px-8 md:px-16 outline-none group/Chatbutton focus-visible:ring-8 focus-visible:ring-lavender/20 pointer-events-auto h-48 min-h-48 md:min-w-80 md:h-80 active:scale-[0.98]", d && "md:translate-x-[40px] focus-visible:translate-x-0", f === "hover" && "group/hoverChatbutton hover:grid-cols-[24px_1fr] hover:translate-x-0", f === "active" && "group/activeChatbutton active:grid-cols-[24px_1fr] active:translate-x-0", "focus-visible:grid-cols-[24px_1fr]", s),
13
+ className: e("chat-border grid grid-cols-[24px_0fr] transition-[grid-template-columns] justify-center items-center overflow-hidden cursor-pointer transition-all rounded-pill px-8 md:px-16 outline-none group/Chatbutton focus-visible:ring-8 focus-visible:ring-lavender/20 pointer-events-auto h-48 min-h-48 md:min-w-80 md:h-80 active:scale-[0.98]", d && "md:translate-x-[40px] focus-visible:translate-x-0", f === "hover" && "group/hoverChatbutton hover:grid-cols-[24px_1fr] hover:translate-x-0", f === "active" && "group/activeChatbutton active:grid-cols-[24px_1fr] active:translate-x-0", "focus-visible:grid-cols-[24px_1fr]", s),
14
14
  children: [/* @__PURE__ */ n(t, {
15
15
  name: "Sparkles",
16
16
  className: e("chat-button-icon w-24 transition-all", d && "relative md:start-[calc(-16px)] group-focus-visible/Chatbutton:start-0 group-hover/hoverChatbutton:start-0 group-active/activeChatbutton:start-0")
@@ -1 +1 @@
1
- {"version":3,"file":"ChatButton.js","names":[],"sources":["../../lib/ui/ChatButton.tsx"],"sourcesContent":["import { Icon } from '@clubmed/trident-icons';\nimport type { ButtonHTMLAttributes } from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nconst DEFAULT_TEASER_COPY = 'Hello, Ask me a question';\nconst FALLBACK_ARIA_LABEL = 'Chat with your assistant';\n\nexport type ChatButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n offset?: boolean;\n unfoldOn?: 'hover' | 'active';\n};\n\nexport function ChatButton({\n children = DEFAULT_TEASER_COPY,\n className,\n type = 'button',\n 'aria-label': ariaLabel,\n tabIndex,\n offset,\n unfoldOn = 'hover',\n ...rest\n}: ChatButtonProps) {\n const label =\n ariaLabel ??\n (typeof children === 'string' && children.trim().length > 0\n ? children.trim()\n : FALLBACK_ARIA_LABEL);\n\n return (\n <button\n type={type}\n aria-label={label}\n tabIndex={tabIndex ?? 0}\n {...rest}\n className={twMerge(\n 'chat-button grid grid-cols-[24px_0fr] transition-[grid-template-columns] justify-center items-center overflow-hidden cursor-pointer transition-all rounded-pill px-8 md:px-16 outline-none group/Chatbutton focus-visible:ring-8 focus-visible:ring-lavender/20 pointer-events-auto h-48 min-h-48 md:min-w-80 md:h-80 active:scale-[0.98]',\n offset && 'md:translate-x-[40px] focus-visible:translate-x-0',\n unfoldOn === 'hover' &&\n 'group/hoverChatbutton hover:grid-cols-[24px_1fr] hover:translate-x-0',\n unfoldOn === 'active' &&\n 'group/activeChatbutton active:grid-cols-[24px_1fr] active:translate-x-0',\n 'focus-visible:grid-cols-[24px_1fr]',\n className,\n )}\n >\n <Icon\n name=\"Sparkles\"\n className={twMerge(\n 'chat-button-icon w-24 transition-all',\n offset &&\n 'relative md:start-[calc(-16px)] group-focus-visible/Chatbutton:start-0 group-hover/hoverChatbutton:start-0 group-active/activeChatbutton:start-0',\n )}\n />\n <div className=\"grid grid-cols-[0fr] overflow-hidden opacity-0 transition-opacity group-hover/hoverChatbutton:opacity-100 group-focus-visible/Chatbutton:opacity-100 group-active/activeChatbutton:opacity-100 duration-500\">\n <span\n aria-hidden=\"true\"\n className=\"chat-button-text items-center ps-20 flex gap-10 whitespace-nowrap font-semibold text-b3 text-black\"\n >\n {children}\n <Icon name=\"ArrowTailRight\" width=\"24px\" />\n </span>\n </div>\n </button>\n );\n}\n"],"mappings":";;;;AAIA,IAAM,IAAsB,4BACtB,IAAsB;AAO5B,SAAgB,EAAW,EACzB,cAAW,GACX,cACA,UAAO,UACP,cAAc,GACd,aACA,WACA,cAAW,SACX,GAAG,KACe;CAClB,IAAM,IACJ,MACC,OAAO,KAAa,YAAY,EAAS,MAAM,CAAC,SAAS,IACtD,EAAS,MAAM,GACf;AAEN,QACE,kBAAC,UAAD;EACQ;EACN,cAAY;EACZ,UAAU,KAAY;EACtB,GAAI;EACJ,WAAW,EACT,6UACA,KAAU,qDACV,MAAa,WACX,wEACF,MAAa,YACX,2EACF,sCACA,EACD;YAdH,CAgBE,kBAAC,GAAD;GACE,MAAK;GACL,WAAW,EACT,wCACA,KACE,mJACH;GACD,CAAA,EACF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,QAAD;IACE,eAAY;IACZ,WAAU;cAFZ,CAIG,GACD,kBAAC,GAAD;KAAM,MAAK;KAAiB,OAAM;KAAS,CAAA,CACtC;;GACH,CAAA,CACC"}
1
+ {"version":3,"file":"ChatButton.js","names":[],"sources":["../../lib/ui/ChatButton.tsx"],"sourcesContent":["import { Icon } from '@clubmed/trident-icons';\nimport type { ButtonHTMLAttributes } from 'react';\nimport { twMerge } from './helpers/twMerge';\n\nconst DEFAULT_TEASER_COPY = 'Hello, Ask me a question';\nconst FALLBACK_ARIA_LABEL = 'Chat with your assistant';\n\nexport type ChatButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n offset?: boolean;\n unfoldOn?: 'hover' | 'active';\n};\n\nexport function ChatButton({\n children = DEFAULT_TEASER_COPY,\n className,\n type = 'button',\n 'aria-label': ariaLabel,\n tabIndex,\n offset,\n unfoldOn = 'hover',\n ...rest\n}: ChatButtonProps) {\n const label =\n ariaLabel ??\n (typeof children === 'string' && children.trim().length > 0\n ? children.trim()\n : FALLBACK_ARIA_LABEL);\n\n return (\n <button\n type={type}\n aria-label={label}\n tabIndex={tabIndex ?? 0}\n {...rest}\n className={twMerge(\n 'chat-border grid grid-cols-[24px_0fr] transition-[grid-template-columns] justify-center items-center overflow-hidden cursor-pointer transition-all rounded-pill px-8 md:px-16 outline-none group/Chatbutton focus-visible:ring-8 focus-visible:ring-lavender/20 pointer-events-auto h-48 min-h-48 md:min-w-80 md:h-80 active:scale-[0.98]',\n offset && 'md:translate-x-[40px] focus-visible:translate-x-0',\n unfoldOn === 'hover' &&\n 'group/hoverChatbutton hover:grid-cols-[24px_1fr] hover:translate-x-0',\n unfoldOn === 'active' &&\n 'group/activeChatbutton active:grid-cols-[24px_1fr] active:translate-x-0',\n 'focus-visible:grid-cols-[24px_1fr]',\n className,\n )}\n >\n <Icon\n name=\"Sparkles\"\n className={twMerge(\n 'chat-button-icon w-24 transition-all',\n offset &&\n 'relative md:start-[calc(-16px)] group-focus-visible/Chatbutton:start-0 group-hover/hoverChatbutton:start-0 group-active/activeChatbutton:start-0',\n )}\n />\n <div className=\"grid grid-cols-[0fr] overflow-hidden opacity-0 transition-opacity group-hover/hoverChatbutton:opacity-100 group-focus-visible/Chatbutton:opacity-100 group-active/activeChatbutton:opacity-100 duration-500\">\n <span\n aria-hidden=\"true\"\n className=\"chat-button-text items-center ps-20 flex gap-10 whitespace-nowrap font-semibold text-b3 text-black\"\n >\n {children}\n <Icon name=\"ArrowTailRight\" width=\"24px\" />\n </span>\n </div>\n </button>\n );\n}\n"],"mappings":";;;;AAIA,IAAM,IAAsB,4BACtB,IAAsB;AAO5B,SAAgB,EAAW,EACzB,cAAW,GACX,cACA,UAAO,UACP,cAAc,GACd,aACA,WACA,cAAW,SACX,GAAG,KACe;CAClB,IAAM,IACJ,MACC,OAAO,KAAa,YAAY,EAAS,MAAM,CAAC,SAAS,IACtD,EAAS,MAAM,GACf;AAEN,QACE,kBAAC,UAAD;EACQ;EACN,cAAY;EACZ,UAAU,KAAY;EACtB,GAAI;EACJ,WAAW,EACT,6UACA,KAAU,qDACV,MAAa,WACX,wEACF,MAAa,YACX,2EACF,sCACA,EACD;YAdH,CAgBE,kBAAC,GAAD;GACE,MAAK;GACL,WAAW,EACT,wCACA,KACE,mJACH;GACD,CAAA,EACF,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,QAAD;IACE,eAAY;IACZ,WAAU;cAFZ,CAIG,GACD,kBAAC,GAAD;KAAM,MAAK;KAAiB,OAAM;KAAS,CAAA,CACtC;;GACH,CAAA,CACC"}
@@ -0,0 +1,10 @@
1
+ import { FormHTMLAttributes } from 'react';
2
+ export interface ChatInputProps extends FormHTMLAttributes<HTMLFormElement> {
3
+ value: string;
4
+ placeholder?: string;
5
+ onValueChange: (value: string) => void;
6
+ onSubmit: () => void;
7
+ /** Fallback for when the browser does not support the Web Speech API */
8
+ onAudioClick?: () => void;
9
+ }
10
+ export declare function ChatInput({ value, placeholder, onValueChange, onSubmit, onAudioClick, className, ...props }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,149 @@
1
+ "use client";
2
+ import { Button as e } from "./buttons/Button.js";
3
+ import { twMerge as t } from "./helpers/twMerge.js";
4
+ import { useEffect as n, useRef as r, useState as i } from "react";
5
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
+ //#region lib/ui/ChatInput.tsx
7
+ var s = 12, c = 48, l = 8;
8
+ function u(e) {
9
+ let t = r(e);
10
+ return n(() => {
11
+ t.current = e;
12
+ }), t;
13
+ }
14
+ var d = 3e3;
15
+ function f(e) {
16
+ let [t, a] = i(!1), [o, s] = i(!1), c = r(null), l = r(null), f = r(!1), p = u(e);
17
+ function m() {
18
+ l.current && clearTimeout(l.current);
19
+ }
20
+ function h() {
21
+ m(), l.current = setTimeout(() => {
22
+ f.current = !1, s(!1), c.current?.stop();
23
+ }, d);
24
+ }
25
+ n(() => {
26
+ let e = window.webkitSpeechRecognition ?? window.SpeechRecognition;
27
+ if (!e) return;
28
+ a(!0);
29
+ let t = new e();
30
+ return t.continuous = !0, t.interimResults = !0, t.lang = navigator.language, t.onresult = (e) => {
31
+ let t = Array.from(e.results).map((e) => e[0].transcript).join("");
32
+ p.current(t), h();
33
+ }, t.onend = () => {
34
+ if (m(), f.current) try {
35
+ t.start();
36
+ } catch {}
37
+ else s(!1);
38
+ }, t.onerror = (e) => {
39
+ (e.error === "not-allowed" || e.error === "aborted") && (f.current = !1, s(!1), m());
40
+ }, c.current = t, () => {
41
+ t.abort(), m();
42
+ };
43
+ }, []);
44
+ function g() {
45
+ let e = c.current;
46
+ e && (f.current ? (f.current = !1, e.stop()) : (f.current = !0, s(!0), e.start(), h()));
47
+ }
48
+ return {
49
+ isSupported: t,
50
+ isListening: o,
51
+ toggle: g
52
+ };
53
+ }
54
+ function p(e) {
55
+ let t = r(null);
56
+ return n(() => {
57
+ let n = t.current;
58
+ if (!e) {
59
+ n && (n.style.height = "0px");
60
+ return;
61
+ }
62
+ let r, i = null, a = null;
63
+ return navigator.mediaDevices.getUserMedia({
64
+ audio: !0,
65
+ video: !1
66
+ }).then((e) => {
67
+ i = e, a = new AudioContext();
68
+ let n = a.createMediaStreamSource(i), o = a.createAnalyser();
69
+ o.fftSize = 256, n.connect(o);
70
+ let s = new Uint8Array(o.frequencyBinCount);
71
+ function c() {
72
+ o.getByteFrequencyData(s);
73
+ let e = s.reduce((e, t) => e + t, 0) / s.length, n = t.current;
74
+ n && (n.style.height = `${Math.sqrt(e / 255) * 10}px`), r = requestAnimationFrame(c);
75
+ }
76
+ r = requestAnimationFrame(c);
77
+ }), () => {
78
+ cancelAnimationFrame(r), i?.getTracks().forEach((e) => e.stop()), a?.close();
79
+ };
80
+ }, [e]), t;
81
+ }
82
+ function m({ value: n, placeholder: r = "Ask a question?", onValueChange: u, onSubmit: d, onAudioClick: m, className: h, ...g }) {
83
+ let [_, v] = i(!1), y = n.trim(), b = _ || y.length > 0, { isSupported: x, isListening: S, toggle: C } = f(u), w = p(S), T = x || !!m, E = T ? c + l + c : c;
84
+ function D() {
85
+ x ? C() : m?.();
86
+ }
87
+ function O(e) {
88
+ e.preventDefault(), y && d();
89
+ }
90
+ return /* @__PURE__ */ o("form", {
91
+ onSubmit: O,
92
+ onMouseDown: (e) => {
93
+ e.target.tagName !== "TEXTAREA" && e.preventDefault();
94
+ },
95
+ ...g,
96
+ style: { paddingBottom: b ? s + l + c : s },
97
+ className: t("relative flex items-start overflow-hidden bg-white border border-light-grey p-12 w-full", "transition-[padding-bottom,border-radius] duration-250 ease-out rounded-b-[24]", b ? "rounded-32" : "rounded-[40]", h),
98
+ children: [/* @__PURE__ */ a("textarea", {
99
+ rows: b ? 3 : 1,
100
+ value: n,
101
+ onChange: (e) => u(e.target.value),
102
+ onKeyDown: (e) => {
103
+ e.key === "Enter" && (e.metaKey || e.ctrlKey) && y && (e.preventDefault(), d());
104
+ },
105
+ onFocus: () => v(!0),
106
+ onBlur: () => v(!1),
107
+ placeholder: r,
108
+ "aria-label": r,
109
+ style: { marginInlineEnd: b ? 0 : E + l },
110
+ className: t("scrollbar-hidden bg-transparent text-b3 py-12 outline-none resize-none w-full px-20 border border-middleGrey", "transition-[margin-inline-end,border-radius] duration-250 ease-out", b ? "text-black rounded-[20]" : "text-darkGrey placeholder:text-darkGrey rounded-[40]")
111
+ }), /* @__PURE__ */ o("div", {
112
+ style: {
113
+ insetInlineStart: b ? `calc(50% - ${E / 2}px)` : `calc(100% - ${s + E}px)`,
114
+ bottom: s
115
+ },
116
+ className: "absolute flex gap-8 items-center transition-[inset-inline-start] duration-250 ease-out",
117
+ children: [/* @__PURE__ */ a(e, {
118
+ type: "submit",
119
+ "aria-label": "Send message",
120
+ disabled: !y,
121
+ variant: "circle",
122
+ color: "saffron",
123
+ icon: "ArrowTailRight",
124
+ iconWidth: "24px"
125
+ }), T && /* @__PURE__ */ a(e, {
126
+ type: "button",
127
+ "aria-label": S ? "Stop recording" : "Use microphone",
128
+ "aria-pressed": S,
129
+ onClick: D,
130
+ variant: "circle",
131
+ theme: S ? "solid" : "outline",
132
+ color: S ? "sienna" : "black",
133
+ icon: "Audio",
134
+ iconWidth: "24px",
135
+ className: t("relative", S && "animate-pulse", !S && "border-lightGrey"),
136
+ children: /* @__PURE__ */ a("span", {
137
+ ref: w,
138
+ "aria-hidden": "true",
139
+ className: "bg-current absolute w-5 bottom-21",
140
+ style: { height: "0px" }
141
+ })
142
+ })]
143
+ })]
144
+ });
145
+ }
146
+ //#endregion
147
+ export { m as ChatInput };
148
+
149
+ //# sourceMappingURL=ChatInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInput.js","names":[],"sources":["../../lib/ui/ChatInput.tsx"],"sourcesContent":["/// <reference types=\"@types/dom-speech-recognition\" />\n'use client';\n\nimport type { FormHTMLAttributes } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { Button } from './buttons/Button';\nimport { twMerge } from './helpers/twMerge';\n\nexport interface ChatInputProps extends FormHTMLAttributes<HTMLFormElement> {\n value: string;\n placeholder?: string;\n onValueChange: (value: string) => void;\n onSubmit: () => void;\n /** Fallback for when the browser does not support the Web Speech API */\n onAudioClick?: () => void;\n}\n\nconst FORM_PAD = 12; // matches p-12\nconst BTN_SIZE = 48; // matches size-48\nconst BTN_GAP = 8; // matches gap-8\n\n// Keep onValueChange stable inside the recognition handler without re-creating the SR instance\nfunction useCallbackRef<T extends (...args: never[]) => unknown>(fn: T) {\n const ref = useRef(fn);\n useEffect(() => {\n ref.current = fn;\n });\n return ref;\n}\n\nconst SILENCE_TIMEOUT_MS = 3_000;\n\nfunction useSpeechRecognition(onValueChange: (v: string) => void) {\n const [isSupported, setIsSupported] = useState(false);\n const [isListening, setIsListening] = useState(false);\n const recognitionRef = useRef<SpeechRecognition | null>(null);\n const silenceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isListeningRef = useRef(false);\n const onValueChangeRef = useCallbackRef(onValueChange);\n\n function clearSilenceTimer() {\n if (silenceTimerRef.current) clearTimeout(silenceTimerRef.current);\n }\n\n function resetSilenceTimer() {\n clearSilenceTimer();\n silenceTimerRef.current = setTimeout(() => {\n isListeningRef.current = false;\n setIsListening(false);\n recognitionRef.current?.stop();\n }, SILENCE_TIMEOUT_MS);\n }\n\n useEffect(() => {\n const SR: typeof SpeechRecognition | undefined =\n (window as Window & { webkitSpeechRecognition?: typeof SpeechRecognition })\n .webkitSpeechRecognition ?? window.SpeechRecognition;\n if (!SR) return;\n\n setIsSupported(true);\n\n const recognition = new SR();\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.lang = navigator.language;\n\n recognition.onresult = (event: SpeechRecognitionEvent) => {\n const transcript = Array.from(event.results)\n .map((r: SpeechRecognitionResult) => r[0].transcript)\n .join('');\n onValueChangeRef.current(transcript);\n resetSilenceTimer();\n };\n\n recognition.onend = () => {\n clearSilenceTimer();\n // Restart automatically if the user hasn't manually stopped (browser cut us off)\n if (isListeningRef.current) {\n try {\n recognition.start();\n } catch {\n /* already starting */\n }\n } else {\n setIsListening(false);\n }\n };\n\n recognition.onerror = (e: SpeechRecognitionErrorEvent) => {\n if (e.error === 'not-allowed' || e.error === 'aborted') {\n isListeningRef.current = false;\n setIsListening(false);\n clearSilenceTimer();\n }\n };\n\n recognitionRef.current = recognition;\n return () => {\n recognition.abort();\n clearSilenceTimer();\n };\n // SR detection and instance creation only needs to run once on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function toggle() {\n const recognition = recognitionRef.current;\n if (!recognition) return;\n if (isListeningRef.current) {\n isListeningRef.current = false;\n recognition.stop();\n } else {\n isListeningRef.current = true;\n setIsListening(true);\n recognition.start();\n resetSilenceTimer();\n }\n }\n\n return { isSupported, isListening, toggle };\n}\n\n/**\n * Drives the audio-level indicator by writing directly to the DOM element's\n * style — avoids triggering a React re-render on every animation frame\n * (rule: rerender-use-ref-transient-values).\n *\n * Returns a ref to attach to the indicator <span>.\n */\nfunction useAudioLevel(isListening: boolean) {\n const indicatorRef = useRef<HTMLSpanElement>(null);\n\n useEffect(() => {\n const el = indicatorRef.current;\n\n if (!isListening) {\n if (el) el.style.height = '0px';\n return;\n }\n\n let animId: number;\n let stream: MediaStream | null = null;\n let ctx: AudioContext | null = null;\n\n navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((s) => {\n stream = s;\n ctx = new AudioContext();\n const source = ctx.createMediaStreamSource(stream);\n const analyser = ctx.createAnalyser();\n analyser.fftSize = 256;\n source.connect(analyser);\n const data = new Uint8Array(analyser.frequencyBinCount);\n\n function tick() {\n analyser.getByteFrequencyData(data);\n const avg = data.reduce((sum, v) => sum + v, 0) / data.length;\n // Square-root curve so quiet sounds register more visibly\n const node = indicatorRef.current;\n if (node) node.style.height = `${Math.sqrt(avg / 255) * 10}px`;\n animId = requestAnimationFrame(tick);\n }\n animId = requestAnimationFrame(tick);\n });\n\n return () => {\n cancelAnimationFrame(animId);\n stream?.getTracks().forEach((t) => t.stop());\n ctx?.close();\n };\n }, [isListening]);\n\n return indicatorRef;\n}\n\nexport function ChatInput({\n value,\n placeholder = 'Ask a question?',\n onValueChange,\n onSubmit,\n onAudioClick,\n className,\n ...props\n}: ChatInputProps) {\n const [isFocused, setIsFocused] = useState(false);\n const trimmed = value.trim();\n const isOpen = isFocused || trimmed.length > 0;\n const { isSupported, isListening, toggle } = useSpeechRecognition(onValueChange);\n const audioIndicatorRef = useAudioLevel(isListening);\n\n const showAudio = isSupported || !!onAudioClick;\n const btnW = showAudio ? BTN_SIZE + BTN_GAP + BTN_SIZE : BTN_SIZE;\n\n function handleAudioClick() {\n if (isSupported) {\n toggle();\n } else {\n onAudioClick?.();\n }\n }\n\n function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n if (trimmed) onSubmit();\n }\n\n return (\n <form\n onSubmit={handleSubmit}\n onMouseDown={(e) => {\n if ((e.target as HTMLElement).tagName !== 'TEXTAREA') e.preventDefault();\n }}\n {...props}\n style={{\n paddingBottom: isOpen ? FORM_PAD + BTN_GAP + BTN_SIZE : FORM_PAD,\n }}\n className={twMerge(\n 'relative flex items-start overflow-hidden bg-white border border-light-grey p-12 w-full',\n 'transition-[padding-bottom,border-radius] duration-250 ease-out rounded-b-[24]',\n isOpen ? 'rounded-32' : 'rounded-[40]',\n className,\n )}\n >\n <textarea\n rows={isOpen ? 3 : 1}\n value={value}\n onChange={(e) => onValueChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && trimmed) {\n e.preventDefault();\n onSubmit();\n }\n }}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n placeholder={placeholder}\n aria-label={placeholder}\n style={{\n marginInlineEnd: isOpen ? 0 : btnW + BTN_GAP,\n }}\n className={twMerge(\n 'scrollbar-hidden bg-transparent text-b3 py-12 outline-none resize-none w-full px-20 border border-middleGrey',\n 'transition-[margin-inline-end,border-radius] duration-250 ease-out',\n isOpen\n ? 'text-black rounded-[20]'\n : 'text-darkGrey placeholder:text-darkGrey rounded-[40]',\n )}\n />\n\n <div\n style={{\n insetInlineStart: isOpen\n ? `calc(50% - ${btnW / 2}px)`\n : `calc(100% - ${FORM_PAD + btnW}px)`,\n bottom: FORM_PAD,\n }}\n className=\"absolute flex gap-8 items-center transition-[inset-inline-start] duration-250 ease-out\"\n >\n <Button\n type=\"submit\"\n aria-label=\"Send message\"\n disabled={!trimmed}\n variant=\"circle\"\n color=\"saffron\"\n icon=\"ArrowTailRight\"\n iconWidth=\"24px\"\n />\n {showAudio && (\n <Button\n type=\"button\"\n aria-label={isListening ? 'Stop recording' : 'Use microphone'}\n aria-pressed={isListening}\n onClick={handleAudioClick}\n variant=\"circle\"\n theme={isListening ? 'solid' : 'outline'}\n color={isListening ? 'sienna' : 'black'}\n icon=\"Audio\"\n iconWidth=\"24px\"\n className={twMerge(\n 'relative',\n isListening && 'animate-pulse',\n !isListening && 'border-lightGrey',\n )}\n >\n <span\n ref={audioIndicatorRef}\n aria-hidden=\"true\"\n className=\"bg-current absolute w-5 bottom-21\"\n style={{ height: '0px' }}\n />\n </Button>\n )}\n </div>\n </form>\n );\n}\n"],"mappings":"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"}