@beautinique/frontend-components 1.0.1 → 1.0.3

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 (42) hide show
  1. package/README.md +49 -1
  2. package/dist/lib/button.d.cts +4 -1
  3. package/dist/lib/button.d.cts.map +1 -1
  4. package/dist/lib/button.d.ts +4 -1
  5. package/dist/lib/button.d.ts.map +1 -1
  6. package/dist/lib/constants.d.cts +4 -0
  7. package/dist/lib/constants.d.cts.map +1 -1
  8. package/dist/lib/constants.d.ts +4 -0
  9. package/dist/lib/constants.d.ts.map +1 -1
  10. package/dist/lib/tooltip.d.cts +36 -4
  11. package/dist/lib/tooltip.d.cts.map +1 -1
  12. package/dist/lib/tooltip.d.ts +36 -4
  13. package/dist/lib/tooltip.d.ts.map +1 -1
  14. package/dist/toast/ToastContainer.d.cts +1 -1
  15. package/dist/toast/ToastContainer.d.cts.map +1 -1
  16. package/dist/toast/ToastContainer.d.ts +1 -1
  17. package/dist/toast/ToastContainer.d.ts.map +1 -1
  18. package/dist/toast/index.cjs +37 -43
  19. package/dist/toast/index.cjs.map +1 -1
  20. package/dist/toast/index.js +24 -30
  21. package/dist/toast/index.js.map +1 -1
  22. package/dist/toast/types.d.cts +2 -2
  23. package/dist/toast/types.d.cts.map +1 -1
  24. package/dist/toast/types.d.ts +2 -2
  25. package/dist/toast/types.d.ts.map +1 -1
  26. package/dist/types/component.d.cts +22 -4
  27. package/dist/types/component.d.cts.map +1 -1
  28. package/dist/types/component.d.ts +22 -4
  29. package/dist/types/component.d.ts.map +1 -1
  30. package/dist/ui/Button.d.cts +1 -1
  31. package/dist/ui/Button.d.cts.map +1 -1
  32. package/dist/ui/Button.d.ts +1 -1
  33. package/dist/ui/Button.d.ts.map +1 -1
  34. package/dist/ui/Tooltip.d.cts +1 -1
  35. package/dist/ui/Tooltip.d.cts.map +1 -1
  36. package/dist/ui/Tooltip.d.ts +1 -1
  37. package/dist/ui/Tooltip.d.ts.map +1 -1
  38. package/dist/ui/index.cjs +144 -62
  39. package/dist/ui/index.cjs.map +1 -1
  40. package/dist/ui/index.js +144 -62
  41. package/dist/ui/index.js.map +1 -1
  42. package/package.json +2 -1
package/README.md CHANGED
@@ -12,6 +12,7 @@ npm install @beautinique/frontend-components @beautinique/frontend-styles @iconi
12
12
  ```
13
13
 
14
14
  Peer dependencies: `react`, `react-dom`, `@iconify/react`, `@beautinique/frontend-styles`.
15
+ It needs `tailwind-merge` too, which comes with it.
15
16
 
16
17
  ## Setup (once per app)
17
18
 
@@ -57,15 +58,62 @@ const App = () => (
57
58
  );
58
59
  ```
59
60
 
61
+ ### Button
62
+
63
+ ```tsx
64
+ const save = <Button pattern="primary" content="Save" buttonProps={{ type: 'submit' }} />;
65
+
66
+ // only an icon: it has to be given a name, a screen reader reads it (`aria-labelledby` works too)
67
+ const edit = (
68
+ <Button
69
+ pattern="outline"
70
+ content={{ icon: 'solar:pen-linear' }}
71
+ buttonProps={{ 'aria-label': 'Edit category' }}
72
+ />
73
+ );
74
+ ```
75
+
76
+ - **Classes you give win over the ones they clash with**, with no `!` (`className="rounded-md px-2"`
77
+ replaces the button's `rounded-lg` and `px-4`). The classes for other screen sizes are other
78
+ classes and stay: the button has `lg:px-5`, so to change the padding on large screens too give
79
+ `lg:px-2` as well. `buttonProps.className` wins over `className`.
80
+ - **`ref`** is the `<button>` itself: `<Button ref={buttonRef} ... />`.
81
+ - A button with only an icon does not compile without `aria-label` or `aria-labelledby` in
82
+ `buttonProps`.
83
+
84
+ ### Tooltip
85
+
86
+ ```tsx
87
+ const hint = (
88
+ <Tooltip title="Save" description="Ctrl + S" placement="right">
89
+ <Button pattern="primary" content="Save" />
90
+ </Tooltip>
91
+ );
92
+ ```
93
+
94
+ - It opens on hover and on focus, and closes on mouse leave, blur or **Escape**.
95
+ - **It stays inside the window**: with no room on the side asked for (`placement`) it opens on the
96
+ opposite side, and it is pushed along the edge to keep 8px from it, the arrow still pointing at
97
+ the content.
98
+ - **For a screen reader** it is `role="tooltip"` and, while it is open, the content is described by it
99
+ (`aria-describedby` is put on the child element, next to what it already has).
100
+ - **`required={false}` shows only the content.** The wrapper stays (as `display: contents`, it takes
101
+ no room), so `required` can change while the page is open (a locked field, the size of the
102
+ screen) without the content being created again and losing its state. One difference to a tooltip
103
+ that is not there at all: the content is one level deeper in the DOM, so a css rule that looks at
104
+ the parent of the content (`space-y-*` on a parent, `> :first-child`) sees the wrapper.
105
+
60
106
  ### Toasts
61
107
 
62
108
  `toaster` works from anywhere (an API client, a store), not only from components:
63
109
 
64
- ```ts
110
+ ```tsx
65
111
  toaster.success({ title: 'Saved', description: 'Your changes were saved.' });
66
112
  toaster.error({ title: 'Failed' });
67
113
  toaster.warning({ title: 'Careful' });
114
+ toaster.default({ title: 'Heads up' });
68
115
  toaster.loading({ title: 'Working' });
116
+ toaster.custom({ type: 'custom', children: <p>Any React content</p> });
69
117
  ```
70
118
 
71
119
  Toasts that follow uploads (`withProgressToast` for one request, `createUploadsToast`,
@@ -1,3 +1,6 @@
1
1
  import type { IButton } from '../types/component.js';
2
- export declare const getButtonCss: (pattern: IButton["pattern"]) => "text-white bg-sky-blue-burst shadow-primary-btn hover:shadow-primary-btn-hover" | "text-secondary-invert bg-secondary shadow-secondary-btn hover:shadow-secondary-btn-hover" | "text-tertiary-invert bg-tertiary shadow-tertiary-btn hover:shadow-tertiary-btn-hover" | "text-primary border border-primary shadow-outline-btn hover:shadow-outline-btn-hover" | "bg-transparent border border-primary/30 text-secondary";
2
+ type TPattern = IButton['pattern'];
3
+ /** The look of a pattern; a pattern nobody knows (from code that is not type checked) is transparent. */
4
+ export declare const getButtonCss: (pattern: TPattern) => string;
5
+ export {};
3
6
  //# sourceMappingURL=button.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.cts","sourceRoot":"","sources":["../../src/lib/button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,eAAO,MAAM,YAAY,GAAI,SAAS,OAAO,CAAC,SAAS,CAAC,+ZAcvD,CAAC"}
1
+ {"version":3,"file":"button.d.cts","sourceRoot":"","sources":["../../src/lib/button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,KAAK,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAYnC,yGAAyG;AACzG,eAAO,MAAM,YAAY,GAAI,SAAS,QAAQ,WACwC,CAAC"}
@@ -1,3 +1,6 @@
1
1
  import type { IButton } from '../types/component.js';
2
- export declare const getButtonCss: (pattern: IButton["pattern"]) => "text-white bg-sky-blue-burst shadow-primary-btn hover:shadow-primary-btn-hover" | "text-secondary-invert bg-secondary shadow-secondary-btn hover:shadow-secondary-btn-hover" | "text-tertiary-invert bg-tertiary shadow-tertiary-btn hover:shadow-tertiary-btn-hover" | "text-primary border border-primary shadow-outline-btn hover:shadow-outline-btn-hover" | "bg-transparent border border-primary/30 text-secondary";
2
+ type TPattern = IButton['pattern'];
3
+ /** The look of a pattern; a pattern nobody knows (from code that is not type checked) is transparent. */
4
+ export declare const getButtonCss: (pattern: TPattern) => string;
5
+ export {};
3
6
  //# sourceMappingURL=button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/lib/button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,eAAO,MAAM,YAAY,GAAI,SAAS,OAAO,CAAC,SAAS,CAAC,+ZAcvD,CAAC"}
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/lib/button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,KAAK,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AAYnC,yGAAyG;AACzG,eAAO,MAAM,YAAY,GAAI,SAAS,QAAQ,WACwC,CAAC"}
@@ -1,5 +1,9 @@
1
1
  export declare const TOOLTIP_GAP: 15;
2
2
  export declare const TOOLTIP_ANIMATION_DURATION: 400;
3
+ /** The least space a tooltip keeps between itself and the edge of the window. */
4
+ export declare const TOOLTIP_VIEWPORT_MARGIN: 8;
5
+ /** The arrow stays at least this far from the ends of the tooltip (its own size and the rounded corner). */
6
+ export declare const TOOLTIP_ARROW_INSET: 16;
3
7
  export declare const TOAST_TYPES: readonly ["success", "error", "warning", "progress", "uploads", "loading", "default", "custom"];
4
8
  export declare const TOAST_TYPE: { [K in (typeof TOAST_TYPES)[number]]: K; };
5
9
  //# sourceMappingURL=constants.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,EAAW,CAAC;AACvC,eAAO,MAAM,0BAA0B,EAAG,GAAY,CAAC;AAEvD,eAAO,MAAM,WAAW,iGASd,CAAC;AAEX,eAAO,MAAM,UAAU,EAAkE,GACtF,CAAC,IAAI,CAAC,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,GACvC,CAAC"}
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,EAAW,CAAC;AACvC,eAAO,MAAM,0BAA0B,EAAG,GAAY,CAAC;AACvD,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,EAAG,CAAU,CAAC;AAClD,4GAA4G;AAC5G,eAAO,MAAM,mBAAmB,EAAG,EAAW,CAAC;AAE/C,eAAO,MAAM,WAAW,iGASd,CAAC;AAEX,eAAO,MAAM,UAAU,EAAkE,GACtF,CAAC,IAAI,CAAC,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,GACvC,CAAC"}
@@ -1,5 +1,9 @@
1
1
  export declare const TOOLTIP_GAP: 15;
2
2
  export declare const TOOLTIP_ANIMATION_DURATION: 400;
3
+ /** The least space a tooltip keeps between itself and the edge of the window. */
4
+ export declare const TOOLTIP_VIEWPORT_MARGIN: 8;
5
+ /** The arrow stays at least this far from the ends of the tooltip (its own size and the rounded corner). */
6
+ export declare const TOOLTIP_ARROW_INSET: 16;
3
7
  export declare const TOAST_TYPES: readonly ["success", "error", "warning", "progress", "uploads", "loading", "default", "custom"];
4
8
  export declare const TOAST_TYPE: { [K in (typeof TOAST_TYPES)[number]]: K; };
5
9
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,EAAW,CAAC;AACvC,eAAO,MAAM,0BAA0B,EAAG,GAAY,CAAC;AAEvD,eAAO,MAAM,WAAW,iGASd,CAAC;AAEX,eAAO,MAAM,UAAU,EAAkE,GACtF,CAAC,IAAI,CAAC,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,GACvC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,EAAW,CAAC;AACvC,eAAO,MAAM,0BAA0B,EAAG,GAAY,CAAC;AACvD,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,EAAG,CAAU,CAAC;AAClD,4GAA4G;AAC5G,eAAO,MAAM,mBAAmB,EAAG,EAAW,CAAC;AAE/C,eAAO,MAAM,WAAW,iGASd,CAAC;AAEX,eAAO,MAAM,UAAU,EAAkE,GACtF,CAAC,IAAI,CAAC,OAAO,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,GACvC,CAAC"}
@@ -1,6 +1,38 @@
1
- import type { CSSProperties } from 'react';
2
1
  import type { ITooltip } from '../types/component.js';
3
- export declare const getTooltipPosition: (rect: DOMRect, placement: NonNullable<ITooltip["placement"]>) => CSSProperties;
4
- export declare const getTooltipTransform: (placement: NonNullable<ITooltip["placement"]>, isVisible: boolean) => string;
5
- export declare const getTooltipArrowCss: (placement: NonNullable<ITooltip["placement"]>) => "after:bottom-full after:left-1/2 after:-translate-x-1/2 after:border-b-silver-jet-2" | "after:top-1/2 after:right-full after:-translate-y-1/2 after:border-r-silver-jet-2" | "after:top-1/2 after:left-full after:-translate-y-1/2 after:border-l-silver-jet-2" | "after:top-full after:left-1/2 after:-translate-x-1/2 after:border-t-silver-jet-2";
2
+ type TPlacement = NonNullable<ITooltip['placement']>;
3
+ export interface ISize {
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface ITooltipLayout {
8
+ /** The side the tooltip really opens on: the opposite one when there is no room on the asked one. */
9
+ placement: TPlacement;
10
+ /** Where the tooltip points to, in the window (it is moved away from it by `getTooltipTransform`). */
11
+ position: {
12
+ top: number;
13
+ left: number;
14
+ };
15
+ /** How far the arrow moves along the tooltip to keep pointing at the content when the tooltip is pushed in. */
16
+ arrowShift: number;
17
+ }
18
+ export declare const getTooltipPosition: (rect: DOMRect, placement: TPlacement) => {
19
+ top: number;
20
+ left: number;
21
+ };
22
+ /**
23
+ * Where the tooltip goes. Without its `size` (it is not on the page yet) it goes where it was asked
24
+ * to. With it, it opens on the opposite side when the asked one has no room and the other has, and
25
+ * it is pushed along that side to stay inside the window; the arrow keeps pointing at the content.
26
+ */
27
+ export declare const getTooltipLayout: ({ rect, placement, size, viewport, }: {
28
+ rect: DOMRect;
29
+ placement: TPlacement;
30
+ size?: ISize;
31
+ viewport: ISize;
32
+ }) => ITooltipLayout;
33
+ /** Whether two layouts put the tooltip in the same place (so there is nothing to change). */
34
+ export declare const isSameTooltipLayout: (a: ITooltipLayout, b: ITooltipLayout) => boolean;
35
+ export declare const getTooltipTransform: (placement: TPlacement, isVisible: boolean) => string;
36
+ export declare const getTooltipArrowCss: (placement: TPlacement) => "after:bottom-full after:left-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:-translate-x-1/2 after:border-b-silver-jet-2" | "after:top-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:right-full after:-translate-y-1/2 after:border-r-silver-jet-2" | "after:top-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:left-full after:-translate-y-1/2 after:border-l-silver-jet-2" | "after:top-full after:left-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:-translate-x-1/2 after:border-t-silver-jet-2";
37
+ export {};
6
38
  //# sourceMappingURL=tooltip.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.d.cts","sourceRoot":"","sources":["../../src/lib/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,eAAO,MAAM,kBAAkB,GAC7B,MAAM,OAAO,EACb,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAC5C,aAYF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAC7C,WAAW,OAAO,WAenB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,0VAY/E,CAAC"}
1
+ {"version":3,"file":"tooltip.d.cts","sourceRoot":"","sources":["../../src/lib/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,KAAK,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAErD,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,qGAAqG;IACrG,SAAS,EAAE,UAAU,CAAC;IACtB,sGAAsG;IACtG,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,+GAA+G;IAC/G,UAAU,EAAE,MAAM,CAAC;CACpB;AAWD,eAAO,MAAM,kBAAkB,GAC7B,MAAM,OAAO,EACb,WAAW,UAAU,KACpB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAY7B,CAAC;AAiBF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,sCAK9B;IACD,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC;CACjB,KAAG,cA2BH,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,GAAI,GAAG,cAAc,EAAE,GAAG,cAAc,YAInC,CAAC;AAEtC,eAAO,MAAM,mBAAmB,GAAI,WAAW,UAAU,EAAE,WAAW,OAAO,WAc5E,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,WAAW,UAAU,8fAYvD,CAAC"}
@@ -1,6 +1,38 @@
1
- import type { CSSProperties } from 'react';
2
1
  import type { ITooltip } from '../types/component.js';
3
- export declare const getTooltipPosition: (rect: DOMRect, placement: NonNullable<ITooltip["placement"]>) => CSSProperties;
4
- export declare const getTooltipTransform: (placement: NonNullable<ITooltip["placement"]>, isVisible: boolean) => string;
5
- export declare const getTooltipArrowCss: (placement: NonNullable<ITooltip["placement"]>) => "after:bottom-full after:left-1/2 after:-translate-x-1/2 after:border-b-silver-jet-2" | "after:top-1/2 after:right-full after:-translate-y-1/2 after:border-r-silver-jet-2" | "after:top-1/2 after:left-full after:-translate-y-1/2 after:border-l-silver-jet-2" | "after:top-full after:left-1/2 after:-translate-x-1/2 after:border-t-silver-jet-2";
2
+ type TPlacement = NonNullable<ITooltip['placement']>;
3
+ export interface ISize {
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface ITooltipLayout {
8
+ /** The side the tooltip really opens on: the opposite one when there is no room on the asked one. */
9
+ placement: TPlacement;
10
+ /** Where the tooltip points to, in the window (it is moved away from it by `getTooltipTransform`). */
11
+ position: {
12
+ top: number;
13
+ left: number;
14
+ };
15
+ /** How far the arrow moves along the tooltip to keep pointing at the content when the tooltip is pushed in. */
16
+ arrowShift: number;
17
+ }
18
+ export declare const getTooltipPosition: (rect: DOMRect, placement: TPlacement) => {
19
+ top: number;
20
+ left: number;
21
+ };
22
+ /**
23
+ * Where the tooltip goes. Without its `size` (it is not on the page yet) it goes where it was asked
24
+ * to. With it, it opens on the opposite side when the asked one has no room and the other has, and
25
+ * it is pushed along that side to stay inside the window; the arrow keeps pointing at the content.
26
+ */
27
+ export declare const getTooltipLayout: ({ rect, placement, size, viewport, }: {
28
+ rect: DOMRect;
29
+ placement: TPlacement;
30
+ size?: ISize;
31
+ viewport: ISize;
32
+ }) => ITooltipLayout;
33
+ /** Whether two layouts put the tooltip in the same place (so there is nothing to change). */
34
+ export declare const isSameTooltipLayout: (a: ITooltipLayout, b: ITooltipLayout) => boolean;
35
+ export declare const getTooltipTransform: (placement: TPlacement, isVisible: boolean) => string;
36
+ export declare const getTooltipArrowCss: (placement: TPlacement) => "after:bottom-full after:left-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:-translate-x-1/2 after:border-b-silver-jet-2" | "after:top-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:right-full after:-translate-y-1/2 after:border-r-silver-jet-2" | "after:top-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:left-full after:-translate-y-1/2 after:border-l-silver-jet-2" | "after:top-full after:left-[calc(50%_+_var(--tooltip-arrow-shift,0px))] after:-translate-x-1/2 after:border-t-silver-jet-2";
37
+ export {};
6
38
  //# sourceMappingURL=tooltip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/lib/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,eAAO,MAAM,kBAAkB,GAC7B,MAAM,OAAO,EACb,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAC5C,aAYF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAC7C,WAAW,OAAO,WAenB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,WAAW,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,0VAY/E,CAAC"}
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/lib/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,KAAK,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AAErD,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,qGAAqG;IACrG,SAAS,EAAE,UAAU,CAAC;IACtB,sGAAsG;IACtG,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,+GAA+G;IAC/G,UAAU,EAAE,MAAM,CAAC;CACpB;AAWD,eAAO,MAAM,kBAAkB,GAC7B,MAAM,OAAO,EACb,WAAW,UAAU,KACpB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAY7B,CAAC;AAiBF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,sCAK9B;IACD,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC;CACjB,KAAG,cA2BH,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,GAAI,GAAG,cAAc,EAAE,GAAG,cAAc,YAInC,CAAC;AAEtC,eAAO,MAAM,mBAAmB,GAAI,WAAW,UAAU,EAAE,WAAW,OAAO,WAc5E,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,WAAW,UAAU,8fAYvD,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { IClassName } from '../types/component.js';
2
2
  import type { TToastItem } from './types.js';
3
- export declare const Toaster: (props: TToastItem & IClassName) => import("react").JSX.Element | null;
3
+ export declare const Toaster: import("react").MemoExoticComponent<(props: TToastItem & IClassName) => import("react").JSX.Element | null>;
4
4
  export declare const ToastContainer: () => import("react").JSX.Element | null;
5
5
  //# sourceMappingURL=ToastContainer.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToastContainer.d.cts","sourceRoot":"","sources":["../../src/toast/ToastContainer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIxD,OAAO,KAAK,EAAuB,UAAU,EAAqB,MAAM,YAAY,CAAC;AAkLrF,eAAO,MAAM,OAAO,GAAI,OAAO,UAAU,GAAG,UAAU,uCAmJrD,CAAC;AAEF,eAAO,MAAM,cAAc,0CAY1B,CAAC"}
1
+ {"version":3,"file":"ToastContainer.d.cts","sourceRoot":"","sources":["../../src/toast/ToastContainer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIxD,OAAO,KAAK,EAAuB,UAAU,EAAqB,MAAM,YAAY,CAAC;AA4UrF,eAAO,MAAM,OAAO,8CA1JQ,UAAU,GAAG,UAAU,wCA0JX,CAAC;AAEzC,eAAO,MAAM,cAAc,0CAY1B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { IClassName } from '../types/component.js';
2
2
  import type { TToastItem } from './types.js';
3
- export declare const Toaster: (props: TToastItem & IClassName) => import("react").JSX.Element | null;
3
+ export declare const Toaster: import("react").MemoExoticComponent<(props: TToastItem & IClassName) => import("react").JSX.Element | null>;
4
4
  export declare const ToastContainer: () => import("react").JSX.Element | null;
5
5
  //# sourceMappingURL=ToastContainer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToastContainer.d.ts","sourceRoot":"","sources":["../../src/toast/ToastContainer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIxD,OAAO,KAAK,EAAuB,UAAU,EAAqB,MAAM,YAAY,CAAC;AAkLrF,eAAO,MAAM,OAAO,GAAI,OAAO,UAAU,GAAG,UAAU,uCAmJrD,CAAC;AAEF,eAAO,MAAM,cAAc,0CAY1B,CAAC"}
1
+ {"version":3,"file":"ToastContainer.d.ts","sourceRoot":"","sources":["../../src/toast/ToastContainer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIxD,OAAO,KAAK,EAAuB,UAAU,EAAqB,MAAM,YAAY,CAAC;AA4UrF,eAAO,MAAM,OAAO,8CA1JQ,UAAU,GAAG,UAAU,wCA0JX,CAAC;AAEzC,eAAO,MAAM,cAAc,0CAY1B,CAAC"}
@@ -2,8 +2,9 @@
2
2
 
3
3
  var nanoid = require('nanoid');
4
4
  var zustand = require('zustand');
5
- var react = require('@iconify/react');
6
- var react$1 = require('react');
5
+ var react$1 = require('@iconify/react');
6
+ var react = require('react');
7
+ var tailwindMerge = require('tailwind-merge');
7
8
  var jsxRuntime = require('react/jsx-runtime');
8
9
 
9
10
  var __defProp = Object.defineProperty;
@@ -108,56 +109,48 @@ var TOAST_ICON_SETS = [
108
109
  }
109
110
  ];
110
111
  var registerToastIcons = /* @__PURE__ */ __name(() => {
111
- for (const iconSet of TOAST_ICON_SETS) react.addCollection(iconSet);
112
+ for (const iconSet of TOAST_ICON_SETS) react$1.addCollection(iconSet);
112
113
  }, "registerToastIcons");
113
114
  var TOAST_ICON_NAMES = TOAST_ICON_SETS.flatMap(
114
115
  ({ prefix, icons }) => Object.keys(icons).map((name) => `${prefix}:${name}`)
115
116
  );
116
117
 
117
118
  // src/lib/button.ts
118
- var getButtonCss = /* @__PURE__ */ __name((pattern) => {
119
- switch (pattern) {
120
- case "primary":
121
- return "text-white bg-sky-blue-burst shadow-primary-btn hover:shadow-primary-btn-hover";
122
- case "secondary":
123
- return "text-secondary-invert bg-secondary shadow-secondary-btn hover:shadow-secondary-btn-hover";
124
- case "tertiary":
125
- return "text-tertiary-invert bg-tertiary shadow-tertiary-btn hover:shadow-tertiary-btn-hover";
126
- case "outline":
127
- return "text-primary border border-primary shadow-outline-btn hover:shadow-outline-btn-hover";
128
- case "transparent":
129
- default:
130
- return "bg-transparent border border-primary/30 text-secondary";
131
- }
132
- }, "getButtonCss");
119
+ var PATTERN_CSS = {
120
+ primary: "text-white bg-sky-blue-burst shadow-primary-btn hover:shadow-primary-btn-hover",
121
+ secondary: "text-secondary-invert bg-secondary shadow-secondary-btn hover:shadow-secondary-btn-hover",
122
+ tertiary: "text-tertiary-invert bg-tertiary shadow-tertiary-btn hover:shadow-tertiary-btn-hover",
123
+ outline: "text-primary border border-primary shadow-outline-btn hover:shadow-outline-btn-hover",
124
+ transparent: "bg-transparent border border-primary/30 text-secondary"
125
+ };
126
+ var getButtonCss = /* @__PURE__ */ __name((pattern) => Object.hasOwn(PATTERN_CSS, pattern) ? PATTERN_CSS[pattern] : PATTERN_CSS.transparent, "getButtonCss");
127
+ var BASE_CSS = "group flex w-full cursor-pointer items-center justify-center gap-1 rounded-lg px-4 py-3 text-sm leading-4 transition-all duration-300 disabled:cursor-not-allowed disabled:opacity-85 lg:px-5 lg:py-4 xl:text-base";
133
128
  var Button = /* @__PURE__ */ __name(({
134
129
  pattern,
135
130
  content,
136
131
  className = "",
137
132
  leftIcon,
138
133
  rightIcon,
139
- buttonProps
140
- }) => {
141
- const btnCSS = getButtonCss(pattern);
142
- const handleClick = /* @__PURE__ */ __name((e) => {
143
- if (buttonProps?.disabled) return;
144
- buttonProps?.onClick?.(e);
145
- }, "handleClick");
146
- return /* @__PURE__ */ jsxRuntime.jsxs(
134
+ buttonProps,
135
+ ref
136
+ }) => (
137
+ // A class that is given wins over the one it clashes with (`rounded-md` over `rounded-lg`),
138
+ // with no `!`; one for another screen size (`lg:px-5`) is a different class and stays.
139
+ /* @__PURE__ */ jsxRuntime.jsxs(
147
140
  "button",
148
141
  {
149
142
  ...buttonProps,
150
- className: `group flex w-full cursor-pointer items-center justify-center gap-1 rounded-lg px-4 py-3 text-sm leading-4 transition-all duration-300 disabled:cursor-not-allowed disabled:opacity-85 lg:px-5 lg:py-4 xl:text-base ${btnCSS} ${className} ${buttonProps?.className ?? ""}`,
143
+ ref,
144
+ className: tailwindMerge.twMerge(BASE_CSS, getButtonCss(pattern), className, buttonProps?.className),
151
145
  type: buttonProps?.type ?? "button",
152
- onClick: handleClick,
153
146
  children: [
154
- leftIcon && /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { ...leftIcon }),
155
- typeof content === "object" ? /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { ...content }) : content,
156
- rightIcon && /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { ...rightIcon })
147
+ leftIcon && /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { ...leftIcon }),
148
+ typeof content === "object" ? /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { ...content }) : content,
149
+ rightIcon && /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { ...rightIcon })
157
150
  ]
158
151
  }
159
- );
160
- }, "Button");
152
+ )
153
+ ), "Button");
161
154
 
162
155
  // src/toast/toaster.ts
163
156
  var { add, update, remove } = useToastStore.getState();
@@ -418,7 +411,7 @@ var UploadRow = /* @__PURE__ */ __name(({ item }) => {
418
411
  const { icon, rgb } = UPLOAD_ITEM_ICON[item.status];
419
412
  return /* @__PURE__ */ jsxRuntime.jsxs("li", { "data-status": item.status, className: "flex items-center gap-1.5 md:gap-2", children: [
420
413
  /* @__PURE__ */ jsxRuntime.jsx(
421
- react.Icon,
414
+ react$1.Icon,
422
415
  {
423
416
  icon,
424
417
  className: "size-3.5 shrink-0 md:size-4",
@@ -478,7 +471,7 @@ var cardConfig = /* @__PURE__ */ __name((type) => {
478
471
  return { iconName: "solar:info-circle-outline", rgb: "var(--primary-rgb)" };
479
472
  }
480
473
  }, "cardConfig");
481
- var Toaster = /* @__PURE__ */ __name((props) => {
474
+ var ToasterItem = /* @__PURE__ */ __name((props) => {
482
475
  const {
483
476
  className = "",
484
477
  type,
@@ -489,9 +482,9 @@ var Toaster = /* @__PURE__ */ __name((props) => {
489
482
  closeTimer = 5e3
490
483
  } = props;
491
484
  const remove2 = useToastStore((s) => s.remove);
492
- const [visible, setVisible] = react$1.useState(false);
493
- const [mounted, setMounted] = react$1.useState(true);
494
- const timeoutRef = react$1.useRef(null);
485
+ const [visible, setVisible] = react.useState(false);
486
+ const [mounted, setMounted] = react.useState(true);
487
+ const timeoutRef = react.useRef(null);
495
488
  const uploadsSummary = props.type === TOAST_TYPE.uploads ? getUploadsSummary(props.items) : null;
496
489
  const isUploadsSettled = uploadsSummary?.isSettled ?? false;
497
490
  let resolvedAutoClose = autoClose;
@@ -506,14 +499,14 @@ var Toaster = /* @__PURE__ */ __name((props) => {
506
499
  resolvedCloseTimer = uploadsSummary.failed > 0 ? 8e3 : 2500;
507
500
  }
508
501
  const config = uploadsSummary ? { iconName: "", rgb: uploadsRgb(uploadsSummary) } : cardConfig(type);
509
- const handleClose = react$1.useCallback(() => {
502
+ const handleClose = react.useCallback(() => {
510
503
  setVisible(false);
511
504
  timeoutRef.current = setTimeout(() => {
512
505
  setMounted(false);
513
506
  remove2(props.id);
514
507
  }, 300);
515
508
  }, [remove2, props.id]);
516
- react$1.useEffect(() => {
509
+ react.useEffect(() => {
517
510
  const enterTimer = setTimeout(() => {
518
511
  setVisible(true);
519
512
  }, 50);
@@ -552,7 +545,7 @@ var Toaster = /* @__PURE__ */ __name((props) => {
552
545
  progress: uploadsSummary.percent,
553
546
  style: { color: `rgb(${config.rgb})` }
554
547
  }
555
- ) : /* @__PURE__ */ jsxRuntime.jsx(react.Icon, { icon: config.iconName, style: { color: `rgb(${config.rgb})` } })),
548
+ ) : /* @__PURE__ */ jsxRuntime.jsx(react$1.Icon, { icon: config.iconName, style: { color: `rgb(${config.rgb})` } })),
556
549
  props.type === TOAST_TYPE.uploads && uploadsSummary ? /* @__PURE__ */ jsxRuntime.jsx(
557
550
  UploadsBody,
558
551
  {
@@ -586,7 +579,7 @@ var Toaster = /* @__PURE__ */ __name((props) => {
586
579
  )
587
580
  ] }),
588
581
  resolvedIsClosable && /* @__PURE__ */ jsxRuntime.jsx(
589
- react.Icon,
582
+ react$1.Icon,
590
583
  {
591
584
  icon: "lucide:x",
592
585
  className: "text-primary cursor-pointer md:size-5",
@@ -596,7 +589,8 @@ var Toaster = /* @__PURE__ */ __name((props) => {
596
589
  ] })
597
590
  }
598
591
  );
599
- }, "Toaster");
592
+ }, "ToasterItem");
593
+ var Toaster = react.memo(ToasterItem);
600
594
  var ToastContainer = /* @__PURE__ */ __name(() => {
601
595
  const toasts = useToastStore((s) => s.toasts);
602
596
  if (toasts.length === 0) return null;