@krizaka/ui 1.3.0 → 2.0.0-beta.1

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 (77) hide show
  1. package/README.md +137 -4
  2. package/dist/alert.d.ts +95 -0
  3. package/dist/alert.js +38 -0
  4. package/dist/alert.js.map +1 -0
  5. package/dist/avatar.d.ts +98 -0
  6. package/dist/avatar.js +48 -0
  7. package/dist/avatar.js.map +1 -0
  8. package/dist/badge.d.ts +64 -0
  9. package/dist/badge.js +31 -0
  10. package/dist/badge.js.map +1 -0
  11. package/dist/button.d.ts +76 -0
  12. package/dist/button.js +46 -0
  13. package/dist/button.js.map +1 -0
  14. package/dist/card.d.ts +227 -0
  15. package/dist/card.js +108 -0
  16. package/dist/card.js.map +1 -0
  17. package/dist/chunk-CPMZS4XA.js +11 -0
  18. package/dist/chunk-CPMZS4XA.js.map +1 -0
  19. package/dist/chunk-J3NC6ER4.js +9 -0
  20. package/dist/chunk-J3NC6ER4.js.map +1 -0
  21. package/dist/chunk-QRG5RYEI.js +49 -0
  22. package/dist/chunk-QRG5RYEI.js.map +1 -0
  23. package/dist/chunk-RLOXWF2G.js +13 -0
  24. package/dist/chunk-RLOXWF2G.js.map +1 -0
  25. package/dist/cn.d.ts +10 -0
  26. package/dist/cn.js +7 -0
  27. package/dist/cn.js.map +1 -0
  28. package/dist/countdown.d.ts +46 -0
  29. package/dist/countdown.js +74 -0
  30. package/dist/countdown.js.map +1 -0
  31. package/dist/dialog.d.ts +155 -0
  32. package/dist/dialog.js +157 -0
  33. package/dist/dialog.js.map +1 -0
  34. package/dist/dropdown-menu.d.ts +71 -0
  35. package/dist/dropdown-menu.js +66 -0
  36. package/dist/dropdown-menu.js.map +1 -0
  37. package/dist/empty-state.d.ts +63 -0
  38. package/dist/empty-state.js +26 -0
  39. package/dist/empty-state.js.map +1 -0
  40. package/dist/field.d.ts +80 -0
  41. package/dist/field.js +47 -0
  42. package/dist/field.js.map +1 -0
  43. package/dist/index.d.ts +6 -6
  44. package/dist/kbd.d.ts +24 -0
  45. package/dist/kbd.js +16 -0
  46. package/dist/kbd.js.map +1 -0
  47. package/dist/page-header.d.ts +77 -0
  48. package/dist/page-header.js +32 -0
  49. package/dist/page-header.js.map +1 -0
  50. package/dist/popover.d.ts +18 -0
  51. package/dist/popover.js +34 -0
  52. package/dist/popover.js.map +1 -0
  53. package/dist/separator.d.ts +24 -0
  54. package/dist/separator.js +17 -0
  55. package/dist/separator.js.map +1 -0
  56. package/dist/skeleton.d.ts +28 -0
  57. package/dist/skeleton.js +18 -0
  58. package/dist/skeleton.js.map +1 -0
  59. package/dist/slot.d.ts +11 -0
  60. package/dist/slot.js +9 -0
  61. package/dist/slot.js.map +1 -0
  62. package/dist/spinner.d.ts +31 -0
  63. package/dist/spinner.js +31 -0
  64. package/dist/spinner.js.map +1 -0
  65. package/dist/stat.d.ts +75 -0
  66. package/dist/stat.js +42 -0
  67. package/dist/stat.js.map +1 -0
  68. package/dist/theme.d.ts +95 -0
  69. package/dist/theme.js +119 -0
  70. package/dist/theme.js.map +1 -0
  71. package/dist/toast.d.ts +32 -0
  72. package/dist/toast.js +49 -0
  73. package/dist/toast.js.map +1 -0
  74. package/dist/tooltip.d.ts +21 -0
  75. package/dist/tooltip.js +44 -0
  76. package/dist/tooltip.js.map +1 -0
  77. package/package.json +333 -7
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spinner/spinner.tsx"],"sourcesContent":["// Server-safe. An indeterminate wait: an SVG ring, announced as a status with its `label`.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const spinnerVariants = tv({\n base: \"shrink-0 text-accent motion-safe:animate-spin\",\n variants: { size: { sm: \"h-4 w-4\", md: \"h-6 w-6\", lg: \"h-10 w-10\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type SpinnerProps = Omit<React.ComponentProps<\"svg\">, \"children\"> &\n VariantProps<typeof spinnerVariants> & {\n /** The accessible name of the wait, e.g. \"Loading\" — passed translated. */\n label: string;\n };\n\n/** A turning ring with `role=\"status\"` (it stops turning under prefers-reduced-motion). */\nexport function Spinner({ label, size, className, ...props }: SpinnerProps) {\n return (\n <svg\n role=\"status\"\n aria-label={label}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n data-size={size ?? \"md\"}\n className={spinnerVariants({ size, className })}\n {...props}\n >\n <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" strokeOpacity=\"0.2\" strokeWidth=\"3\" />\n <path d=\"M21 12a9 9 0 0 0-9-9\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n"],"mappings":";AAEA,SAAS,UAA6B;AAiBlC,SASE,KATF;AAfG,IAAM,kBAAkB,GAAG;AAAA,EAChC,MAAM;AAAA,EACN,UAAU,EAAE,MAAM,EAAE,IAAI,WAAW,IAAI,WAAW,IAAI,YAAY,EAAE;AAAA,EACpE,iBAAiB,EAAE,MAAM,KAAK;AAChC,CAAC;AASM,SAAS,QAAQ,EAAE,OAAO,MAAM,WAAW,GAAG,MAAM,GAAiB;AAC1E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,aAAW,QAAQ;AAAA,MACnB,WAAW,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAAA,MAC7C,GAAG;AAAA,MAEJ;AAAA,4BAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI,QAAO,gBAAe,eAAc,OAAM,aAAY,KAAI;AAAA,QACxF,oBAAC,UAAK,GAAE,wBAAuB,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ;AAAA;AAAA;AAAA,EAC7F;AAEJ;","names":[]}
package/dist/stat.d.ts ADDED
@@ -0,0 +1,75 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+
4
+ declare const stat: tailwind_variants.TVReturnType<{
5
+ trend: {
6
+ up: {
7
+ trend: string;
8
+ };
9
+ down: {
10
+ trend: string;
11
+ };
12
+ flat: {
13
+ trend: string;
14
+ };
15
+ };
16
+ }, {
17
+ root: string;
18
+ label: string;
19
+ value: string;
20
+ meta: string;
21
+ trend: string;
22
+ hint: string;
23
+ }, undefined, {
24
+ trend: {
25
+ up: {
26
+ trend: string;
27
+ };
28
+ down: {
29
+ trend: string;
30
+ };
31
+ flat: {
32
+ trend: string;
33
+ };
34
+ };
35
+ }, {
36
+ root: string;
37
+ label: string;
38
+ value: string;
39
+ meta: string;
40
+ trend: string;
41
+ hint: string;
42
+ }, tailwind_variants.TVReturnTypeLike<{
43
+ trend: {
44
+ up: {
45
+ trend: string;
46
+ };
47
+ down: {
48
+ trend: string;
49
+ };
50
+ flat: {
51
+ trend: string;
52
+ };
53
+ };
54
+ }, {
55
+ root: string;
56
+ label: string;
57
+ value: string;
58
+ meta: string;
59
+ trend: string;
60
+ hint: string;
61
+ }>>;
62
+ type StatTrend = "up" | "down" | "flat";
63
+ type StatProps = Omit<React.ComponentProps<"div">, "children"> & {
64
+ label: React.ReactNode;
65
+ value: React.ReactNode;
66
+ /** A line under the value: the period, the comparison. */
67
+ hint?: React.ReactNode;
68
+ /** The direction of the change; its arrow is decorative. */
69
+ trend?: StatTrend;
70
+ /** The change, in words, as read and shown (e.g. "+12 % vs last week") — the arrow alone says nothing. */
71
+ trendLabel?: React.ReactNode;
72
+ };
73
+ declare function Stat({ label, value, hint, trend, trendLabel, className, ...props }: StatProps): React.JSX.Element;
74
+
75
+ export { Stat, type StatProps, type StatTrend, stat };
package/dist/stat.js ADDED
@@ -0,0 +1,42 @@
1
+ // src/stat/stat.tsx
2
+ import { tv } from "tailwind-variants";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var stat = tv({
5
+ slots: {
6
+ root: "flex min-w-0 flex-col gap-1",
7
+ label: "text-xs font-semibold uppercase tracking-wider text-fg-secondary",
8
+ value: "font-display text-2xl font-black tabular-nums text-fg",
9
+ meta: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs",
10
+ // The status tokens are too light for small text on a light surface: the words stay a text role, the arrow carries
11
+ // the direction's colour.
12
+ trend: "inline-flex items-center gap-1 font-semibold text-fg [&>svg]:h-3.5 [&>svg]:w-3.5 [&>svg]:shrink-0",
13
+ hint: "text-fg-secondary"
14
+ },
15
+ variants: {
16
+ trend: {
17
+ up: { trend: "[&>svg]:text-success" },
18
+ down: { trend: "[&>svg]:text-danger" },
19
+ flat: { trend: "[&>svg]:text-fg-secondary" }
20
+ }
21
+ }
22
+ });
23
+ var ARROW = { up: "M7 17 17 7M8 7h9v9", down: "M7 7l10 10M17 8v9H8", flat: "M5 12h14M13 6l6 6-6 6" };
24
+ function Stat({ label, value, hint, trend, trendLabel, className, ...props }) {
25
+ const s = stat({ trend });
26
+ return /* @__PURE__ */ jsxs("div", { "data-trend": trend, className: s.root({ className }), ...props, children: [
27
+ /* @__PURE__ */ jsx("p", { className: s.label(), children: label }),
28
+ /* @__PURE__ */ jsx("p", { className: s.value(), children: value }),
29
+ (trendLabel || hint) && /* @__PURE__ */ jsxs("p", { className: s.meta(), children: [
30
+ trend && trendLabel && /* @__PURE__ */ jsxs("span", { className: s.trend(), children: [
31
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: ARROW[trend] }) }),
32
+ trendLabel
33
+ ] }),
34
+ hint && /* @__PURE__ */ jsx("span", { className: s.hint(), children: hint })
35
+ ] })
36
+ ] });
37
+ }
38
+ export {
39
+ Stat,
40
+ stat
41
+ };
42
+ //# sourceMappingURL=stat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stat/stat.tsx"],"sourcesContent":["// Server-safe. A key figure: a label, the value in tabular digits, a hint, a trend. Every word is a prop.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const stat = tv({\n slots: {\n root: \"flex min-w-0 flex-col gap-1\",\n label: \"text-xs font-semibold uppercase tracking-wider text-fg-secondary\",\n value: \"font-display text-2xl font-black tabular-nums text-fg\",\n meta: \"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs\",\n // The status tokens are too light for small text on a light surface: the words stay a text role, the arrow carries\n // the direction's colour.\n trend: \"inline-flex items-center gap-1 font-semibold text-fg [&>svg]:h-3.5 [&>svg]:w-3.5 [&>svg]:shrink-0\",\n hint: \"text-fg-secondary\",\n },\n variants: {\n trend: {\n up: { trend: \"[&>svg]:text-success\" },\n down: { trend: \"[&>svg]:text-danger\" },\n flat: { trend: \"[&>svg]:text-fg-secondary\" },\n },\n },\n});\n\nexport type StatTrend = \"up\" | \"down\" | \"flat\";\n\nconst ARROW: Record<StatTrend, string> = { up: \"M7 17 17 7M8 7h9v9\", down: \"M7 7l10 10M17 8v9H8\", flat: \"M5 12h14M13 6l6 6-6 6\" };\n\nexport type StatProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n label: React.ReactNode;\n value: React.ReactNode;\n /** A line under the value: the period, the comparison. */\n hint?: React.ReactNode;\n /** The direction of the change; its arrow is decorative. */\n trend?: StatTrend;\n /** The change, in words, as read and shown (e.g. \"+12 % vs last week\") — the arrow alone says nothing. */\n trendLabel?: React.ReactNode;\n};\n\nexport function Stat({ label, value, hint, trend, trendLabel, className, ...props }: StatProps) {\n const s = stat({ trend });\n return (\n <div data-trend={trend} className={s.root({ className })} {...props}>\n <p className={s.label()}>{label}</p>\n <p className={s.value()}>{value}</p>\n {(trendLabel || hint) && (\n <p className={s.meta()}>\n {trend && trendLabel && (\n <span className={s.trend()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={ARROW[trend]} />\n </svg>\n {trendLabel}\n </span>\n )}\n {hint && <span className={s.hint()}>{hint}</span>}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";AAEA,SAAS,UAAU;AAyCb,cAKM,YALN;AAvCC,IAAM,OAAO,GAAG;AAAA,EACrB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM;AAAA;AAAA;AAAA,IAGN,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACR,OAAO;AAAA,MACL,IAAI,EAAE,OAAO,uBAAuB;AAAA,MACpC,MAAM,EAAE,OAAO,sBAAsB;AAAA,MACrC,MAAM,EAAE,OAAO,4BAA4B;AAAA,IAC7C;AAAA,EACF;AACF,CAAC;AAID,IAAM,QAAmC,EAAE,IAAI,sBAAsB,MAAM,uBAAuB,MAAM,wBAAwB;AAazH,SAAS,KAAK,EAAE,OAAO,OAAO,MAAM,OAAO,YAAY,WAAW,GAAG,MAAM,GAAc;AAC9F,QAAM,IAAI,KAAK,EAAE,MAAM,CAAC;AACxB,SACE,qBAAC,SAAI,cAAY,OAAO,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC5D;AAAA,wBAAC,OAAE,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,IAChC,oBAAC,OAAE,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,KAC9B,cAAc,SACd,qBAAC,OAAE,WAAW,EAAE,KAAK,GAClB;AAAA,eAAS,cACR,qBAAC,UAAK,WAAW,EAAE,MAAM,GACvB;AAAA,4BAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACnI,8BAAC,UAAK,GAAG,MAAM,KAAK,GAAG,GACzB;AAAA,QACC;AAAA,SACH;AAAA,MAED,QAAQ,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,gBAAK;AAAA,OAC5C;AAAA,KAEJ;AAEJ;","names":[]}
@@ -0,0 +1,95 @@
1
+ import * as React from 'react';
2
+ import * as tailwind_variants from 'tailwind-variants';
3
+ import { VariantProps } from 'tailwind-variants';
4
+
5
+ declare const buttonVariants: tailwind_variants.TVReturnType<{
6
+ variant: {
7
+ primary: "bg-accent text-on-accent shadow-sm hover:bg-accent-hover";
8
+ secondary: "border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3";
9
+ outline: "border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent";
10
+ ghost: "text-fg-secondary hover:bg-surface-2 hover:text-fg";
11
+ danger: "border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20";
12
+ };
13
+ size: {
14
+ sm: "h-8 px-3 text-xs";
15
+ md: "h-10 px-4 text-sm";
16
+ lg: "h-12 px-6 text-sm";
17
+ icon: "h-10 w-10";
18
+ };
19
+ shape: {
20
+ rounded: "rounded-lg";
21
+ pill: "rounded-full";
22
+ };
23
+ }, undefined, string, {
24
+ variant: {
25
+ primary: "bg-accent text-on-accent shadow-sm hover:bg-accent-hover";
26
+ secondary: "border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3";
27
+ outline: "border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent";
28
+ ghost: "text-fg-secondary hover:bg-surface-2 hover:text-fg";
29
+ danger: "border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20";
30
+ };
31
+ size: {
32
+ sm: "h-8 px-3 text-xs";
33
+ md: "h-10 px-4 text-sm";
34
+ lg: "h-12 px-6 text-sm";
35
+ icon: "h-10 w-10";
36
+ };
37
+ shape: {
38
+ rounded: "rounded-lg";
39
+ pill: "rounded-full";
40
+ };
41
+ }, undefined, tailwind_variants.TVReturnTypeLike<{
42
+ variant: {
43
+ primary: "bg-accent text-on-accent shadow-sm hover:bg-accent-hover";
44
+ secondary: "border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3";
45
+ outline: "border border-border-default bg-transparent text-fg hover:border-accent hover:text-accent";
46
+ ghost: "text-fg-secondary hover:bg-surface-2 hover:text-fg";
47
+ danger: "border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20";
48
+ };
49
+ size: {
50
+ sm: "h-8 px-3 text-xs";
51
+ md: "h-10 px-4 text-sm";
52
+ lg: "h-12 px-6 text-sm";
53
+ icon: "h-10 w-10";
54
+ };
55
+ shape: {
56
+ rounded: "rounded-lg";
57
+ pill: "rounded-full";
58
+ };
59
+ }, undefined>>;
60
+ type ButtonVariants = VariantProps<typeof buttonVariants>;
61
+
62
+ type Mode = "dark" | "light" | "system";
63
+ /**
64
+ * In <head>, before anything renders: applies the persisted mode and named theme, so the page never flashes.
65
+ * `nonce` for a strict Content-Security-Policy.
66
+ */
67
+ declare function ThemeScript({ nonce }: {
68
+ nonce?: string;
69
+ }): React.JSX.Element;
70
+ type ThemeContextValue = {
71
+ /** The chosen mode: dark, light or follow the system. */
72
+ mode: Mode;
73
+ setMode: (mode: Mode) => void;
74
+ /** The named theme (`html.theme-<name>`), or null. */
75
+ theme: string | null;
76
+ setTheme: (theme: string | null) => void;
77
+ };
78
+ type ThemeProviderProps = {
79
+ children: React.ReactNode;
80
+ /** The mode before anything is persisted. */
81
+ defaultMode?: Mode;
82
+ };
83
+ declare function ThemeProvider({ children, defaultMode }: ThemeProviderProps): React.JSX.Element;
84
+ declare function useTheme(): ThemeContextValue;
85
+ type ThemeToggleProps = Omit<React.ComponentProps<"button">, "onClick" | "children"> & Pick<ButtonVariants, "variant" | "shape"> & {
86
+ /** The accessible name — a string, or one per current mode (e.g. `(mode) => t("theme." + mode)`). */
87
+ label: string | ((mode: Mode) => string);
88
+ };
89
+ /**
90
+ * An icon button (styled as `IconButton`, without its Slot) that cycles dark → light → system. Needs a
91
+ * <ThemeProvider> above it. State: `data-mode`.
92
+ */
93
+ declare function ThemeToggle({ label, variant, shape, className, ...props }: ThemeToggleProps): React.JSX.Element;
94
+
95
+ export { type Mode, type ThemeContextValue, ThemeProvider, type ThemeProviderProps, ThemeScript, ThemeToggle, type ThemeToggleProps, useTheme };
package/dist/theme.js ADDED
@@ -0,0 +1,119 @@
1
+ "use client";
2
+ import {
3
+ buttonVariants
4
+ } from "./chunk-QRG5RYEI.js";
5
+
6
+ // src/theme/theme.tsx
7
+ import * as React from "react";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ var MODE_KEY = "kz-theme";
10
+ var NAME_KEY = "kz-theme-name";
11
+ var MODES = ["dark", "light", "system"];
12
+ var DARK_QUERY = "(prefers-color-scheme: dark)";
13
+ var isMode = (value) => MODES.includes(value);
14
+ var memory = /* @__PURE__ */ new Map();
15
+ function read(key) {
16
+ try {
17
+ return localStorage.getItem(key);
18
+ } catch {
19
+ return memory.get(key) ?? null;
20
+ }
21
+ }
22
+ function write(key, value) {
23
+ if (value === null) memory.delete(key);
24
+ else memory.set(key, value);
25
+ try {
26
+ if (value === null) localStorage.removeItem(key);
27
+ else localStorage.setItem(key, value);
28
+ } catch {
29
+ }
30
+ }
31
+ var listeners = /* @__PURE__ */ new Set();
32
+ var notify = () => listeners.forEach((listener) => listener());
33
+ function subscribe(listener) {
34
+ listeners.add(listener);
35
+ window.addEventListener("storage", listener);
36
+ return () => {
37
+ listeners.delete(listener);
38
+ window.removeEventListener("storage", listener);
39
+ };
40
+ }
41
+ function applyMode(mode) {
42
+ const dark = window.matchMedia(DARK_QUERY).matches;
43
+ document.documentElement.classList.toggle("light", mode === "light" || mode === "system" && !dark);
44
+ }
45
+ function applyName(previous, next) {
46
+ const classes = document.documentElement.classList;
47
+ if (previous) classes.remove(`theme-${previous}`);
48
+ if (next) classes.add(`theme-${next}`);
49
+ }
50
+ function ThemeScript({ nonce }) {
51
+ const js = `(function(){try{var m=localStorage.getItem("${MODE_KEY}")||"system";var n=localStorage.getItem("${NAME_KEY}");var d=matchMedia("${DARK_QUERY}").matches;var c=document.documentElement.classList;c.toggle("light",m==="light"||(m==="system"&&!d));if(n)c.add("theme-"+n)}catch(e){}})()`;
52
+ return /* @__PURE__ */ jsx("script", { nonce, dangerouslySetInnerHTML: { __html: js } });
53
+ }
54
+ var ThemeContext = React.createContext(null);
55
+ function ThemeProvider({ children, defaultMode = "system" }) {
56
+ const stored = React.useSyncExternalStore(subscribe, () => read(MODE_KEY), () => null);
57
+ const mode = isMode(stored) ? stored : defaultMode;
58
+ const theme = React.useSyncExternalStore(subscribe, () => read(NAME_KEY), () => null);
59
+ React.useEffect(() => {
60
+ if (mode !== "system") return;
61
+ const query = window.matchMedia(DARK_QUERY);
62
+ const onChange = () => applyMode("system");
63
+ query.addEventListener?.("change", onChange);
64
+ return () => query.removeEventListener?.("change", onChange);
65
+ }, [mode]);
66
+ const setMode = React.useCallback((next) => {
67
+ write(MODE_KEY, next);
68
+ applyMode(next);
69
+ notify();
70
+ }, []);
71
+ const setTheme = React.useCallback((next) => {
72
+ applyName(read(NAME_KEY), next);
73
+ write(NAME_KEY, next);
74
+ notify();
75
+ }, []);
76
+ const value = React.useMemo(() => ({ mode, setMode, theme, setTheme }), [mode, setMode, theme, setTheme]);
77
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
78
+ }
79
+ function useTheme() {
80
+ const context = React.useContext(ThemeContext);
81
+ if (!context) throw new Error("useTheme: wrap the app in <ThemeProvider>");
82
+ return context;
83
+ }
84
+ var ICONS = {
85
+ dark: /* @__PURE__ */ jsx("path", { d: "M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z" }),
86
+ light: /* @__PURE__ */ jsxs(Fragment, { children: [
87
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "4" }),
88
+ /* @__PURE__ */ jsx("path", { d: "M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" })
89
+ ] }),
90
+ system: /* @__PURE__ */ jsxs(Fragment, { children: [
91
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "12", rx: "2" }),
92
+ /* @__PURE__ */ jsx("path", { d: "M8 20h8M12 16v4" })
93
+ ] })
94
+ };
95
+ function ThemeToggle({ label, variant = "ghost", shape, className, ...props }) {
96
+ const { mode, setMode } = useTheme();
97
+ const next = MODES[(MODES.indexOf(mode) + 1) % MODES.length];
98
+ const name = typeof label === "function" ? label(mode) : label;
99
+ return /* @__PURE__ */ jsx(
100
+ "button",
101
+ {
102
+ type: "button",
103
+ "aria-label": name,
104
+ title: name,
105
+ "data-mode": mode,
106
+ onClick: () => setMode(next),
107
+ className: buttonVariants({ variant, shape, size: "icon", className }),
108
+ ...props,
109
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-5 w-5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: ICONS[mode] })
110
+ }
111
+ );
112
+ }
113
+ export {
114
+ ThemeProvider,
115
+ ThemeScript,
116
+ ThemeToggle,
117
+ useTheme
118
+ };
119
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/theme.tsx"],"sourcesContent":["// Client. ONE mechanism for the whole organisation: dark by default, `html.light` for light, `html.theme-<name>` for a\n// named theme, persisted in localStorage (`kz-theme` for the mode, `kz-theme-name` for the named theme).\nimport * as React from \"react\";\n\nimport { type ButtonVariants, buttonVariants } from \"../button/button\";\n\nexport type Mode = \"dark\" | \"light\" | \"system\";\n\nconst MODE_KEY = \"kz-theme\";\nconst NAME_KEY = \"kz-theme-name\";\nconst MODES: readonly Mode[] = [\"dark\", \"light\", \"system\"];\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nconst isMode = (value: unknown): value is Mode => MODES.includes(value as Mode);\n\n// Storage blocked (private mode, sandbox): the choice lives in memory for the page.\nconst memory = new Map<string, string>();\n\nfunction read(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return memory.get(key) ?? null;\n }\n}\n\nfunction write(key: string, value: string | null) {\n if (value === null) memory.delete(key);\n else memory.set(key, value);\n try {\n if (value === null) localStorage.removeItem(key);\n else localStorage.setItem(key, value);\n } catch {\n // storage blocked: memory holds it\n }\n}\n\n// The persisted choice is an external store: every provider and tab reads the same value, the server reads none.\nconst listeners = new Set<() => void>();\nconst notify = () => listeners.forEach((listener) => listener());\nfunction subscribe(listener: () => void) {\n listeners.add(listener);\n window.addEventListener(\"storage\", listener);\n return () => {\n listeners.delete(listener);\n window.removeEventListener(\"storage\", listener);\n };\n}\n\nfunction applyMode(mode: Mode) {\n const dark = window.matchMedia(DARK_QUERY).matches;\n document.documentElement.classList.toggle(\"light\", mode === \"light\" || (mode === \"system\" && !dark));\n}\n\nfunction applyName(previous: string | null, next: string | null) {\n const classes = document.documentElement.classList;\n if (previous) classes.remove(`theme-${previous}`);\n if (next) classes.add(`theme-${next}`);\n}\n\n/**\n * In <head>, before anything renders: applies the persisted mode and named theme, so the page never flashes.\n * `nonce` for a strict Content-Security-Policy.\n */\nexport function ThemeScript({ nonce }: { nonce?: string }) {\n const js =\n `(function(){try{var m=localStorage.getItem(\"${MODE_KEY}\")||\"system\";var n=localStorage.getItem(\"${NAME_KEY}\");` +\n `var d=matchMedia(\"${DARK_QUERY}\").matches;var c=document.documentElement.classList;` +\n `c.toggle(\"light\",m===\"light\"||(m===\"system\"&&!d));if(n)c.add(\"theme-\"+n)}catch(e){}})()`;\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: js }} />;\n}\n\nexport type ThemeContextValue = {\n /** The chosen mode: dark, light or follow the system. */\n mode: Mode;\n setMode: (mode: Mode) => void;\n /** The named theme (`html.theme-<name>`), or null. */\n theme: string | null;\n setTheme: (theme: string | null) => void;\n};\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null);\n\nexport type ThemeProviderProps = {\n children: React.ReactNode;\n /** The mode before anything is persisted. */\n defaultMode?: Mode;\n};\n\nexport function ThemeProvider({ children, defaultMode = \"system\" }: ThemeProviderProps) {\n // Before hydration the server knows nothing persisted (ThemeScript has already applied it to <html>).\n const stored = React.useSyncExternalStore(subscribe, () => read(MODE_KEY), () => null);\n const mode: Mode = isMode(stored) ? stored : defaultMode;\n const theme = React.useSyncExternalStore(subscribe, () => read(NAME_KEY), () => null);\n\n // \"system\" follows the operating system while the page is open.\n React.useEffect(() => {\n if (mode !== \"system\") return;\n const query = window.matchMedia(DARK_QUERY);\n const onChange = () => applyMode(\"system\");\n query.addEventListener?.(\"change\", onChange);\n return () => query.removeEventListener?.(\"change\", onChange);\n }, [mode]);\n\n const setMode = React.useCallback((next: Mode) => {\n write(MODE_KEY, next);\n applyMode(next);\n notify();\n }, []);\n\n const setTheme = React.useCallback((next: string | null) => {\n applyName(read(NAME_KEY), next);\n write(NAME_KEY, next);\n notify();\n }, []);\n\n const value = React.useMemo(() => ({ mode, setMode, theme, setTheme }), [mode, setMode, theme, setTheme]);\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext);\n if (!context) throw new Error(\"useTheme: wrap the app in <ThemeProvider>\");\n return context;\n}\n\nconst ICONS: Record<Mode, React.ReactNode> = {\n dark: <path d=\"M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z\" />,\n light: (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </>\n ),\n system: (\n <>\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" />\n <path d=\"M8 20h8M12 16v4\" />\n </>\n ),\n};\n\nexport type ThemeToggleProps = Omit<React.ComponentProps<\"button\">, \"onClick\" | \"children\"> &\n Pick<ButtonVariants, \"variant\" | \"shape\"> & {\n /** The accessible name — a string, or one per current mode (e.g. `(mode) => t(\"theme.\" + mode)`). */\n label: string | ((mode: Mode) => string);\n };\n\n/**\n * An icon button (styled as `IconButton`, without its Slot) that cycles dark → light → system. Needs a\n * <ThemeProvider> above it. State: `data-mode`.\n */\nexport function ThemeToggle({ label, variant = \"ghost\", shape, className, ...props }: ThemeToggleProps) {\n const { mode, setMode } = useTheme();\n const next = MODES[(MODES.indexOf(mode) + 1) % MODES.length] as Mode;\n const name = typeof label === \"function\" ? label(mode) : label;\n return (\n <button\n type=\"button\"\n aria-label={name}\n title={name}\n data-mode={mode}\n onClick={() => setMode(next)}\n className={buttonVariants({ variant, shape, size: \"icon\", className })}\n {...props}\n >\n <svg viewBox=\"0 0 24 24\" className=\"h-5 w-5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n {ICONS[mode]}\n </svg>\n </button>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,32 @@
1
+ import * as React from 'react';
2
+ import { ToasterProps as ToasterProps$1 } from 'sonner';
3
+ export { ExternalToast, toast } from 'sonner';
4
+
5
+ declare const toastClassNames: {
6
+ toast: string;
7
+ default: string;
8
+ title: string;
9
+ description: string;
10
+ content: string;
11
+ icon: string;
12
+ success: string;
13
+ warning: string;
14
+ error: string;
15
+ info: string;
16
+ loading: string;
17
+ actionButton: string;
18
+ cancelButton: string;
19
+ closeButton: string;
20
+ };
21
+ type ToasterProps = Omit<ToasterProps$1, "richColors" | "theme" | "containerAriaLabel" | "toastOptions"> & {
22
+ /** The accessible name of the notifications region (sonner's `containerAriaLabel`) — passed translated. */
23
+ label: string;
24
+ /** The accessible name of each toast's close button — passed translated. */
25
+ closeLabel: string;
26
+ /** Extra options for every toast (duration, a className); the class names are merged with the platform's. */
27
+ toastOptions?: Omit<NonNullable<ToasterProps$1["toastOptions"]>, "unstyled" | "closeButtonAriaLabel">;
28
+ };
29
+ /** Mount once, in the root layout. Then call `toast()`, `toast.success/warning/error/info`, `toast.custom(…)`. */
30
+ declare function Toaster({ label, closeLabel, position, closeButton, toastOptions, ...props }: ToasterProps): React.JSX.Element;
31
+
32
+ export { Toaster, type ToasterProps, toastClassNames };
package/dist/toast.js ADDED
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-RLOXWF2G.js";
5
+
6
+ // src/toast/toast.tsx
7
+ import { Toaster as Sonner } from "sonner";
8
+ import { toast } from "sonner";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var tone = (color) => cn("border-l-4", color);
11
+ var toastClassNames = {
12
+ toast: "group pointer-events-auto relative flex w-full items-start gap-3 rounded-xl border border-border-default bg-surface-2 p-4 pr-10 text-sm text-fg shadow-lg",
13
+ default: "",
14
+ title: "font-semibold text-fg",
15
+ description: "mt-0.5 text-xs text-fg-secondary",
16
+ content: "flex min-w-0 flex-1 flex-col",
17
+ icon: "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center [&>svg]:h-4 [&>svg]:w-4",
18
+ success: tone("border-l-success [&_[data-icon]]:text-success"),
19
+ warning: tone("border-l-warning [&_[data-icon]]:text-warning"),
20
+ error: tone("border-l-danger [&_[data-icon]]:text-danger"),
21
+ info: tone("border-l-info [&_[data-icon]]:text-info"),
22
+ loading: "",
23
+ actionButton: "ml-auto shrink-0 self-center rounded-lg bg-accent px-3 py-1.5 text-xs font-semibold text-on-accent hover:bg-accent-hover focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
24
+ cancelButton: "shrink-0 self-center rounded-lg px-3 py-1.5 text-xs font-semibold text-fg-secondary hover:bg-surface-3 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
25
+ closeButton: "absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full text-fg-secondary hover:bg-surface-3 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [&>svg]:h-3.5 [&>svg]:w-3.5"
26
+ };
27
+ function Toaster({ label, closeLabel, position = "bottom-right", closeButton = true, toastOptions, ...props }) {
28
+ const extra = toastOptions?.classNames ?? {};
29
+ const classNames = Object.fromEntries(
30
+ Object.entries(toastClassNames).map(([key, value]) => [key, cn(value, extra[key])])
31
+ );
32
+ return /* @__PURE__ */ jsx(
33
+ Sonner,
34
+ {
35
+ position,
36
+ closeButton,
37
+ containerAriaLabel: label,
38
+ richColors: false,
39
+ toastOptions: { ...toastOptions, unstyled: true, closeButtonAriaLabel: closeLabel, classNames },
40
+ ...props
41
+ }
42
+ );
43
+ }
44
+ export {
45
+ Toaster,
46
+ toast,
47
+ toastClassNames
48
+ };
49
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toast/toast.tsx"],"sourcesContent":["// Client. sonner does the queue, the stacking, the swipe, the timers, the live region and the hotkey; the look is\n// ours: sonner's own styling is off (`unstyled`) and every part reads a role. The status tones are soft (a tinted\n// border and a coloured icon, the text stays `text-fg`): the invariant status tokens are too light for small text.\nimport { Toaster as Sonner, type ToasterProps as SonnerProps } from \"sonner\";\n\nimport { cn } from \"../cn\";\n\nexport type { ExternalToast } from \"sonner\";\nexport { toast } from \"sonner\";\n\nconst tone = (color: string) => cn(\"border-l-4\", color);\n\nexport const toastClassNames = {\n toast:\n \"group pointer-events-auto relative flex w-full items-start gap-3 rounded-xl border border-border-default bg-surface-2 p-4 pr-10 \" +\n \"text-sm text-fg shadow-lg\",\n default: \"\",\n title: \"font-semibold text-fg\",\n description: \"mt-0.5 text-xs text-fg-secondary\",\n content: \"flex min-w-0 flex-1 flex-col\",\n icon: \"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center [&>svg]:h-4 [&>svg]:w-4\",\n success: tone(\"border-l-success [&_[data-icon]]:text-success\"),\n warning: tone(\"border-l-warning [&_[data-icon]]:text-warning\"),\n error: tone(\"border-l-danger [&_[data-icon]]:text-danger\"),\n info: tone(\"border-l-info [&_[data-icon]]:text-info\"),\n loading: \"\",\n actionButton:\n \"ml-auto shrink-0 self-center rounded-lg bg-accent px-3 py-1.5 text-xs font-semibold text-on-accent hover:bg-accent-hover \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n cancelButton:\n \"shrink-0 self-center rounded-lg px-3 py-1.5 text-xs font-semibold text-fg-secondary hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n closeButton:\n \"absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full text-fg-secondary hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [&>svg]:h-3.5 [&>svg]:w-3.5\",\n} satisfies NonNullable<NonNullable<SonnerProps[\"toastOptions\"]>[\"classNames\"]>;\n\nexport type ToasterProps = Omit<SonnerProps, \"richColors\" | \"theme\" | \"containerAriaLabel\" | \"toastOptions\"> & {\n /** The accessible name of the notifications region (sonner's `containerAriaLabel`) — passed translated. */\n label: string;\n /** The accessible name of each toast's close button — passed translated. */\n closeLabel: string;\n /** Extra options for every toast (duration, a className); the class names are merged with the platform's. */\n toastOptions?: Omit<NonNullable<SonnerProps[\"toastOptions\"]>, \"unstyled\" | \"closeButtonAriaLabel\">;\n};\n\n/** Mount once, in the root layout. Then call `toast()`, `toast.success/warning/error/info`, `toast.custom(…)`. */\nexport function Toaster({ label, closeLabel, position = \"bottom-right\", closeButton = true, toastOptions, ...props }: ToasterProps) {\n const extra = toastOptions?.classNames ?? {};\n const classNames = Object.fromEntries(\n Object.entries(toastClassNames).map(([key, value]) => [key, cn(value, extra[key as keyof typeof extra])]),\n ) as typeof toastClassNames;\n return (\n <Sonner\n position={position}\n closeButton={closeButton}\n containerAriaLabel={label}\n richColors={false}\n toastOptions={{ ...toastOptions, unstyled: true, closeButtonAriaLabel: closeLabel, classNames }}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;AAGA,SAAS,WAAW,cAAgD;AAKpE,SAAS,aAAa;AA6ClB;AA3CJ,IAAM,OAAO,CAAC,UAAkB,GAAG,cAAc,KAAK;AAE/C,IAAM,kBAAkB;AAAA,EAC7B,OACE;AAAA,EAEF,SAAS;AAAA,EACT,OAAO;AAAA,EACP,aAAa;AAAA,EACb,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS,KAAK,+CAA+C;AAAA,EAC7D,SAAS,KAAK,+CAA+C;AAAA,EAC7D,OAAO,KAAK,6CAA6C;AAAA,EACzD,MAAM,KAAK,yCAAyC;AAAA,EACpD,SAAS;AAAA,EACT,cACE;AAAA,EAEF,cACE;AAAA,EAEF,aACE;AAEJ;AAYO,SAAS,QAAQ,EAAE,OAAO,YAAY,WAAW,gBAAgB,cAAc,MAAM,cAAc,GAAG,MAAM,GAAiB;AAClI,QAAM,QAAQ,cAAc,cAAc,CAAC;AAC3C,QAAM,aAAa,OAAO;AAAA,IACxB,OAAO,QAAQ,eAAe,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,GAAG,OAAO,MAAM,GAAyB,CAAC,CAAC,CAAC;AAAA,EAC1G;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,oBAAoB;AAAA,MACpB,YAAY;AAAA,MACZ,cAAc,EAAE,GAAG,cAAc,UAAU,MAAM,sBAAsB,YAAY,WAAW;AAAA,MAC7F,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -0,0 +1,21 @@
1
+ import { Tooltip as Tooltip$1 } from 'radix-ui';
2
+ import * as React from 'react';
3
+
4
+ /** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */
5
+ declare const TooltipProvider: React.FC<Tooltip$1.TooltipProviderProps>;
6
+ type TooltipProps = Omit<React.ComponentProps<typeof Tooltip$1.Content>, "content" | "children"> & {
7
+ /** What the tooltip says — passed translated. */
8
+ content: React.ReactNode;
9
+ /** The trigger, rendered as is (`asChild`): a focusable element. */
10
+ children: React.ReactNode;
11
+ open?: boolean;
12
+ defaultOpen?: boolean;
13
+ onOpenChange?: (open: boolean) => void;
14
+ /** Hover delay in ms before it opens (300 by default). */
15
+ delayDuration?: number;
16
+ /** The element the portal renders into (default: document.body). */
17
+ container?: HTMLElement | null;
18
+ };
19
+ declare function Tooltip({ content, children, open, defaultOpen, onOpenChange, delayDuration, container, sideOffset, collisionPadding, className, ...props }: TooltipProps): React.JSX.Element;
20
+
21
+ export { Tooltip, type TooltipProps, TooltipProvider };
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import {
3
+ floating
4
+ } from "./chunk-J3NC6ER4.js";
5
+ import {
6
+ cn
7
+ } from "./chunk-RLOXWF2G.js";
8
+
9
+ // src/tooltip/tooltip.tsx
10
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ var TooltipProvider = TooltipPrimitive.Provider;
13
+ function Tooltip({
14
+ content,
15
+ children,
16
+ open,
17
+ defaultOpen,
18
+ onOpenChange,
19
+ delayDuration = 300,
20
+ container,
21
+ sideOffset = 6,
22
+ collisionPadding = 8,
23
+ className,
24
+ ...props
25
+ }) {
26
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsxs(TooltipPrimitive.Root, { open, defaultOpen, onOpenChange, children: [
27
+ /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { asChild: true, children }),
28
+ /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { container, children: /* @__PURE__ */ jsx(
29
+ TooltipPrimitive.Content,
30
+ {
31
+ sideOffset,
32
+ collisionPadding,
33
+ className: cn(floating, "max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)", className),
34
+ ...props,
35
+ children: content
36
+ }
37
+ ) })
38
+ ] }) });
39
+ }
40
+ export {
41
+ Tooltip,
42
+ TooltipProvider
43
+ };
44
+ //# sourceMappingURL=tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tooltip/tooltip.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n"],"mappings":";;;;;;;;;AAEA,SAAS,WAAW,wBAAwB;AAsCtC,SACE,KADF;AA/BC,IAAM,kBAAkB,iBAAiB;AAgBzC,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB;AAAA,EACA,GAAG;AACL,GAAiB;AACf,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,eACzB,+BAAC,iBAAiB,MAAjB,EAAsB,MAAY,aAA0B,cAC3D;AAAA,wBAAC,iBAAiB,SAAjB,EAAyB,SAAO,MAAE,UAAS;AAAA,IAC5C,oBAAC,iBAAiB,QAAjB,EAAwB,WACvB;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,WAAW,GAAG,UAAU,gGAAgG,SAAS;AAAA,QAChI,GAAG;AAAA,QAEH;AAAA;AAAA,IACH,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}