asterui 0.12.62 → 0.12.64

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 (127) hide show
  1. package/dist/components/Anchor.d.ts +2 -0
  2. package/dist/components/Anchor.js +79 -75
  3. package/dist/components/Anchor.js.map +1 -1
  4. package/dist/components/Autocomplete.d.ts +1 -0
  5. package/dist/components/Autocomplete.js +115 -110
  6. package/dist/components/Autocomplete.js.map +1 -1
  7. package/dist/components/Breadcrumb.d.ts +4 -2
  8. package/dist/components/Breadcrumb.js +54 -29
  9. package/dist/components/Breadcrumb.js.map +1 -1
  10. package/dist/components/Button.d.ts +5 -1
  11. package/dist/components/Button.js +117 -107
  12. package/dist/components/Button.js.map +1 -1
  13. package/dist/components/Chart.d.ts +1 -0
  14. package/dist/components/Chart.js +31 -30
  15. package/dist/components/Chart.js.map +1 -1
  16. package/dist/components/Chat.d.ts +1 -0
  17. package/dist/components/Chat.js +32 -30
  18. package/dist/components/Chat.js.map +1 -1
  19. package/dist/components/Collapse.js +58 -56
  20. package/dist/components/Collapse.js.map +1 -1
  21. package/dist/components/Command.d.ts +5 -2
  22. package/dist/components/Command.js +262 -233
  23. package/dist/components/Command.js.map +1 -1
  24. package/dist/components/ContextMenu.d.ts +4 -0
  25. package/dist/components/ContextMenu.js +149 -130
  26. package/dist/components/ContextMenu.js.map +1 -1
  27. package/dist/components/DatePicker.d.ts +19 -1
  28. package/dist/components/DatePicker.js +266 -87
  29. package/dist/components/DatePicker.js.map +1 -1
  30. package/dist/components/Dock.d.ts +2 -0
  31. package/dist/components/Dock.js +70 -46
  32. package/dist/components/Dock.js.map +1 -1
  33. package/dist/components/FileInput.d.ts +1 -0
  34. package/dist/components/FileInput.js +26 -26
  35. package/dist/components/FileInput.js.map +1 -1
  36. package/dist/components/Filter.d.ts +1 -0
  37. package/dist/components/Filter.js +43 -40
  38. package/dist/components/Filter.js.map +1 -1
  39. package/dist/components/Flex.d.ts +1 -0
  40. package/dist/components/Flex.js +43 -42
  41. package/dist/components/Flex.js.map +1 -1
  42. package/dist/components/FloatButton.d.ts +3 -0
  43. package/dist/components/FloatButton.js +178 -127
  44. package/dist/components/FloatButton.js.map +1 -1
  45. package/dist/components/Input.d.ts +1 -0
  46. package/dist/components/Input.js +201 -184
  47. package/dist/components/Input.js.map +1 -1
  48. package/dist/components/Loading.d.ts +1 -0
  49. package/dist/components/Loading.js +40 -37
  50. package/dist/components/Loading.js.map +1 -1
  51. package/dist/components/Masonry.d.ts +1 -0
  52. package/dist/components/Masonry.js +45 -42
  53. package/dist/components/Masonry.js.map +1 -1
  54. package/dist/components/Mention.d.ts +1 -0
  55. package/dist/components/Mention.js +95 -91
  56. package/dist/components/Mention.js.map +1 -1
  57. package/dist/components/Menu.d.ts +1 -1
  58. package/dist/components/Menu.js +99 -93
  59. package/dist/components/Menu.js.map +1 -1
  60. package/dist/components/Modal.js +26 -17
  61. package/dist/components/Modal.js.map +1 -1
  62. package/dist/components/MonthCalendar.d.ts +1 -0
  63. package/dist/components/MonthCalendar.js +104 -97
  64. package/dist/components/MonthCalendar.js.map +1 -1
  65. package/dist/components/Notification.js +53 -45
  66. package/dist/components/Notification.js.map +1 -1
  67. package/dist/components/QRCode.d.ts +1 -0
  68. package/dist/components/QRCode.js +84 -55
  69. package/dist/components/QRCode.js.map +1 -1
  70. package/dist/components/RadialProgress.d.ts +1 -0
  71. package/dist/components/RadialProgress.js +19 -17
  72. package/dist/components/RadialProgress.js.map +1 -1
  73. package/dist/components/Range.d.ts +1 -0
  74. package/dist/components/Range.js +45 -43
  75. package/dist/components/Range.js.map +1 -1
  76. package/dist/components/Rating.d.ts +4 -2
  77. package/dist/components/Rating.js +83 -79
  78. package/dist/components/Rating.js.map +1 -1
  79. package/dist/components/Responsive.d.ts +4 -2
  80. package/dist/components/Responsive.js +10 -9
  81. package/dist/components/Responsive.js.map +1 -1
  82. package/dist/components/Result.d.ts +1 -0
  83. package/dist/components/Result.js +24 -22
  84. package/dist/components/Result.js.map +1 -1
  85. package/dist/components/Select.d.ts +1 -0
  86. package/dist/components/Select.js +72 -62
  87. package/dist/components/Select.js.map +1 -1
  88. package/dist/components/Splitter.d.ts +2 -0
  89. package/dist/components/Splitter.js +137 -131
  90. package/dist/components/Splitter.js.map +1 -1
  91. package/dist/components/Stat.d.ts +4 -2
  92. package/dist/components/Stat.js +19 -18
  93. package/dist/components/Stat.js.map +1 -1
  94. package/dist/components/Steps.d.ts +4 -2
  95. package/dist/components/Steps.js +56 -52
  96. package/dist/components/Steps.js.map +1 -1
  97. package/dist/components/Tabs.js +69 -57
  98. package/dist/components/Tabs.js.map +1 -1
  99. package/dist/components/TextRotate.d.ts +1 -0
  100. package/dist/components/TextRotate.js +14 -12
  101. package/dist/components/TextRotate.js.map +1 -1
  102. package/dist/components/Textarea.d.ts +1 -0
  103. package/dist/components/Textarea.js +31 -30
  104. package/dist/components/Textarea.js.map +1 -1
  105. package/dist/components/ThemeController.d.ts +6 -3
  106. package/dist/components/ThemeController.js +101 -92
  107. package/dist/components/ThemeController.js.map +1 -1
  108. package/dist/components/Tooltip.js +38 -35
  109. package/dist/components/Tooltip.js.map +1 -1
  110. package/dist/components/Transfer.js +130 -121
  111. package/dist/components/Transfer.js.map +1 -1
  112. package/dist/components/TreeSelect.js +49 -48
  113. package/dist/components/TreeSelect.js.map +1 -1
  114. package/dist/components/Typography.d.ts +10 -5
  115. package/dist/components/Typography.js +84 -81
  116. package/dist/components/Typography.js.map +1 -1
  117. package/dist/components/VirtualList.d.ts +2 -1
  118. package/dist/components/VirtualList.js +40 -36
  119. package/dist/components/VirtualList.js.map +1 -1
  120. package/dist/components/Watermark.d.ts +1 -0
  121. package/dist/components/Watermark.js +74 -71
  122. package/dist/components/Watermark.js.map +1 -1
  123. package/dist/components/WeekCalendar.d.ts +1 -0
  124. package/dist/components/WeekCalendar.js +91 -76
  125. package/dist/components/WeekCalendar.js.map +1 -1
  126. package/dist/index.d.ts +1 -1
  127. package/package.json +1 -1
@@ -1,121 +1,124 @@
1
- import { jsxs as R, jsx as Y } from "react/jsx-runtime";
2
- import { useState as D, useMemo as A, useEffect as M } from "react";
3
- import { useTheme as U } from "../hooks/useTheme.js";
4
- const B = "asterui", X = 0.22;
5
- function _(r, l) {
6
- const n = Math.round(l * 255).toString(16).padStart(2, "0");
1
+ import { jsxs as D, jsx as M } from "react/jsx-runtime";
2
+ import { useState as U, useMemo as F, useEffect as B } from "react";
3
+ import { useTheme as X } from "../hooks/useTheme.js";
4
+ const _ = "asterui", K = 0.22;
5
+ function q(r, c) {
6
+ const n = Math.round(c * 255).toString(16).padStart(2, "0");
7
7
  return r + n;
8
8
  }
9
- const K = (r, l) => {
9
+ const G = (r, c) => {
10
10
  const n = r?.fontSize ?? 16;
11
11
  return {
12
- color: l,
12
+ color: c,
13
13
  fontSize: n,
14
14
  fontWeight: r?.fontWeight ?? 600,
15
15
  fontStyle: r?.fontStyle ?? "normal",
16
16
  fontFamily: r?.fontFamily ?? "sans-serif",
17
17
  lineHeight: r?.lineHeight ?? n * 1.2
18
18
  };
19
- }, q = ({
19
+ }, J = ({
20
20
  children: r,
21
- className: l = "",
21
+ className: c = "",
22
22
  style: n,
23
- content: c,
24
- image: v,
25
- width: a = 120,
23
+ content: d,
24
+ image: x,
25
+ width: s = 120,
26
26
  height: i = 64,
27
- gap: E,
27
+ gap: $,
28
28
  offset: k,
29
- rotate: F = -22,
30
- zIndex: I = 1e3,
29
+ rotate: b = -22,
30
+ zIndex: H = 1e3,
31
31
  font: y,
32
- ...b
32
+ "data-testid": h,
33
+ ...I
33
34
  }) => {
34
- const [m, L] = D(null), d = E?.[0] ?? 120, f = E?.[1] ?? 120, H = k?.[0] ?? d / 2, N = k?.[1] ?? f / 2, { colors: P } = U(), h = A(
35
- () => typeof c == "string" ? [c] : Array.isArray(c) ? c : [B],
36
- [c]
37
- ), W = y?.color ?? _(P.foreground, X), s = A(
38
- () => K(y, W),
39
- [y, W]
40
- ), S = Math.PI / 180 * F, j = h.join("|");
41
- M(() => {
35
+ const [u, L] = U(null), f = $?.[0] ?? 120, m = $?.[1] ?? 120, N = k?.[0] ?? f / 2, P = k?.[1] ?? m / 2, { colors: j } = X(), S = F(
36
+ () => typeof d == "string" ? [d] : Array.isArray(d) ? d : [_],
37
+ [d]
38
+ ), T = y?.color ?? q(j.foreground, K), a = F(
39
+ () => G(y, T),
40
+ [y, T]
41
+ ), E = Math.PI / 180 * b, z = S.join("|");
42
+ B(() => {
42
43
  if (typeof window > "u") return;
43
- let u = !1;
44
- const o = window.devicePixelRatio || 1, $ = a + d, T = i + f, g = document.createElement("canvas");
45
- g.width = $ * o, g.height = T * o;
46
- const e = g.getContext("2d");
47
- if (!e) return;
48
- const w = () => {
49
- const t = g.toDataURL();
50
- u || L({ url: t, width: $, height: T });
51
- }, C = () => {
52
- e.save(), e.translate((d / 2 + a / 2) * o, (f / 2 + i / 2) * o), e.rotate(S), e.fillStyle = s.color, e.textAlign = "center", e.textBaseline = "middle", e.font = `${s.fontStyle} normal ${s.fontWeight} ${s.fontSize * o}px ${s.fontFamily}`;
53
- const t = s.lineHeight * o, p = -((h.length - 1) * t) / 2;
54
- h.forEach((x, O) => {
55
- e.fillText(x, 0, p + O * t);
56
- }), e.restore();
44
+ let l = !1;
45
+ const o = window.devicePixelRatio || 1, W = s + f, w = i + m, g = document.createElement("canvas");
46
+ g.width = W * o, g.height = w * o;
47
+ const t = g.getContext("2d");
48
+ if (!t) return;
49
+ const A = () => {
50
+ const e = g.toDataURL();
51
+ l || L({ url: e, width: W, height: w });
52
+ }, R = () => {
53
+ t.save(), t.translate((f / 2 + s / 2) * o, (m / 2 + i / 2) * o), t.rotate(E), t.fillStyle = a.color, t.textAlign = "center", t.textBaseline = "middle", t.font = `${a.fontStyle} normal ${a.fontWeight} ${a.fontSize * o}px ${a.fontFamily}`;
54
+ const e = a.lineHeight * o, p = -((S.length - 1) * e) / 2;
55
+ S.forEach((v, Y) => {
56
+ t.fillText(v, 0, p + Y * e);
57
+ }), t.restore();
57
58
  };
58
- if (v) {
59
- const t = new Image();
60
- t.crossOrigin = "anonymous", t.referrerPolicy = "no-referrer";
59
+ if (x) {
60
+ const e = new Image();
61
+ e.crossOrigin = "anonymous", e.referrerPolicy = "no-referrer";
61
62
  const p = () => {
62
- e.save(), e.translate((d / 2 + a / 2) * o, (f / 2 + i / 2) * o), e.rotate(S), e.drawImage(
63
- t,
64
- -a / 2 * o,
63
+ t.save(), t.translate((f / 2 + s / 2) * o, (m / 2 + i / 2) * o), t.rotate(E), t.drawImage(
64
+ e,
65
+ -s / 2 * o,
65
66
  -i / 2 * o,
66
- a * o,
67
+ s * o,
67
68
  i * o
68
- ), e.restore(), w();
69
- }, x = () => {
70
- u || L(null);
69
+ ), t.restore(), A();
70
+ }, v = () => {
71
+ l || L(null);
71
72
  };
72
- return t.addEventListener("load", p), t.addEventListener("error", x), t.src = v, () => {
73
- u = !0, t.removeEventListener("load", p), t.removeEventListener("error", x);
73
+ return e.addEventListener("load", p), e.addEventListener("error", v), e.src = x, () => {
74
+ l = !0, e.removeEventListener("load", p), e.removeEventListener("error", v);
74
75
  };
75
76
  } else
76
- C(), w();
77
+ R(), A();
77
78
  return () => {
78
- u = !0;
79
+ l = !0;
79
80
  };
80
81
  }, [
81
- s,
82
- d,
82
+ a,
83
83
  f,
84
+ m,
84
85
  i,
85
- v,
86
- S,
87
- j,
88
- a
86
+ x,
87
+ E,
88
+ z,
89
+ s
89
90
  ]);
90
- const z = ["relative", l].filter(Boolean).join(" ");
91
- return /* @__PURE__ */ R(
91
+ const C = ["relative", c].filter(Boolean).join(" "), O = (l) => h ? `${h}-${l}` : void 0;
92
+ return /* @__PURE__ */ D(
92
93
  "div",
93
94
  {
94
- className: z,
95
+ className: C,
95
96
  style: { position: n?.position ?? "relative", ...n },
96
- ...b,
97
+ "data-testid": h,
98
+ ...I,
97
99
  children: [
98
100
  r,
99
- m && /* @__PURE__ */ Y(
101
+ u && /* @__PURE__ */ M(
100
102
  "div",
101
103
  {
102
104
  "aria-hidden": !0,
103
105
  className: "pointer-events-none absolute inset-0",
104
106
  style: {
105
- zIndex: I,
106
- backgroundImage: `url(${m.url})`,
107
+ zIndex: H,
108
+ backgroundImage: `url(${u.url})`,
107
109
  backgroundRepeat: "repeat",
108
- backgroundSize: `${m.width}px ${m.height}px`,
109
- backgroundPosition: `${H}px ${N}px`
110
- }
110
+ backgroundSize: `${u.width}px ${u.height}px`,
111
+ backgroundPosition: `${N}px ${P}px`
112
+ },
113
+ "data-testid": O("overlay")
111
114
  }
112
115
  )
113
116
  ]
114
117
  }
115
118
  );
116
119
  };
117
- q.displayName = "Watermark";
120
+ J.displayName = "Watermark";
118
121
  export {
119
- q as Watermark
122
+ J as Watermark
120
123
  };
121
124
  //# sourceMappingURL=Watermark.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Watermark.js","sources":["../../src/components/Watermark.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react'\nimport { useTheme } from '../hooks/useTheme'\n\nexport type WatermarkGap = [number, number]\nexport type WatermarkOffset = [number, number]\n\nexport interface WatermarkFontOptions {\n /** Text color for watermark content */\n color?: string\n /** Font size in pixels */\n fontSize?: number\n /** Font weight for watermark text */\n fontWeight?: number | 'normal' | 'bold' | 'bolder' | 'lighter'\n /** Font style for watermark text */\n fontStyle?: 'normal' | 'italic' | 'oblique'\n /** Font family for watermark text */\n fontFamily?: string\n /** Line height in pixels for multi-line content */\n lineHeight?: number\n}\n\nexport interface WatermarkProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'content'> {\n /** Text to render inside the watermark; falls back to \"asterui\" */\n content?: string | string[]\n /** Image source (URL or base64) to render instead of text */\n image?: string\n /** Width of a single watermark tile in pixels */\n width?: number\n /** Height of a single watermark tile in pixels */\n height?: number\n /** Horizontal/vertical gap between watermarks in pixels */\n gap?: WatermarkGap\n /** Offset for the first watermark tile from the top-left corner */\n offset?: WatermarkOffset\n /** Rotation angle in degrees */\n rotate?: number\n /** z-index for the overlay layer */\n zIndex?: number\n /** Font settings for text watermarks */\n font?: WatermarkFontOptions\n /** Content to protect with the watermark */\n children?: React.ReactNode\n}\n\ntype WatermarkImage = {\n url: string\n width: number\n height: number\n}\n\nconst DEFAULT_CONTENT = 'asterui'\nconst DEFAULT_OPACITY = 0.22\n\n// Add opacity to a hex color (returns #rrggbbaa format)\nfunction hexWithOpacity(hex: string, opacity: number): string {\n const alpha = Math.round(opacity * 255).toString(16).padStart(2, '0')\n return hex + alpha\n}\n\nconst getFontSettings = (font: WatermarkFontOptions | undefined, resolvedColor: string) => {\n const fontSize = font?.fontSize ?? 16\n\n return {\n color: resolvedColor,\n fontSize,\n fontWeight: font?.fontWeight ?? 600,\n fontStyle: font?.fontStyle ?? 'normal',\n fontFamily: font?.fontFamily ?? 'sans-serif',\n lineHeight: font?.lineHeight ?? fontSize * 1.2,\n }\n}\n\nexport const Watermark: React.FC<WatermarkProps> = ({\n children,\n className = '',\n style,\n content,\n image,\n width = 120,\n height = 64,\n gap,\n offset,\n rotate = -22,\n zIndex = 1000,\n font,\n ...rest\n}) => {\n const [watermark, setWatermark] = useState<WatermarkImage | null>(null)\n\n const gapX = gap?.[0] ?? 120\n const gapY = gap?.[1] ?? 120\n const offsetX = offset?.[0] ?? gapX / 2\n const offsetY = offset?.[1] ?? gapY / 2\n const { colors } = useTheme()\n const textLines = useMemo(\n () =>\n typeof content === 'string'\n ? [content]\n : Array.isArray(content)\n ? content\n : [DEFAULT_CONTENT],\n [content]\n )\n // Use provided color or theme foreground with opacity\n const resolvedColor = font?.color ?? hexWithOpacity(colors.foreground, DEFAULT_OPACITY)\n const fontSettings = useMemo(\n () => getFontSettings(font, resolvedColor),\n [font, resolvedColor]\n )\n const rotationInRadians = (Math.PI / 180) * rotate\n const textKey = textLines.join('|')\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n let cancelled = false\n const ratio = window.devicePixelRatio || 1\n const tileWidth = width + gapX\n const tileHeight = height + gapY\n const canvas = document.createElement('canvas')\n canvas.width = tileWidth * ratio\n canvas.height = tileHeight * ratio\n const ctx = canvas.getContext('2d')\n\n if (!ctx) return\n\n const commitWatermark = () => {\n const url = canvas.toDataURL()\n if (!cancelled) {\n setWatermark({ url, width: tileWidth, height: tileHeight })\n }\n }\n\n const drawText = () => {\n ctx.save()\n ctx.translate((gapX / 2 + width / 2) * ratio, (gapY / 2 + height / 2) * ratio)\n ctx.rotate(rotationInRadians)\n ctx.fillStyle = fontSettings.color\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.font = `${fontSettings.fontStyle} normal ${fontSettings.fontWeight} ${fontSettings.fontSize * ratio}px ${fontSettings.fontFamily}`\n\n const lineHeight = fontSettings.lineHeight * ratio\n const startY = -((textLines.length - 1) * lineHeight) / 2\n\n textLines.forEach((line, index) => {\n ctx.fillText(line, 0, startY + index * lineHeight)\n })\n\n ctx.restore()\n }\n\n if (image) {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.referrerPolicy = 'no-referrer'\n\n const handleLoad = () => {\n ctx.save()\n ctx.translate((gapX / 2 + width / 2) * ratio, (gapY / 2 + height / 2) * ratio)\n ctx.rotate(rotationInRadians)\n ctx.drawImage(\n img,\n (-width / 2) * ratio,\n (-height / 2) * ratio,\n width * ratio,\n height * ratio\n )\n ctx.restore()\n commitWatermark()\n }\n\n const handleError = () => {\n if (!cancelled) setWatermark(null)\n }\n\n img.addEventListener('load', handleLoad)\n img.addEventListener('error', handleError)\n img.src = image\n\n return () => {\n cancelled = true\n img.removeEventListener('load', handleLoad)\n img.removeEventListener('error', handleError)\n }\n } else {\n drawText()\n commitWatermark()\n }\n\n return () => {\n cancelled = true\n }\n }, [\n fontSettings,\n gapX,\n gapY,\n height,\n image,\n rotationInRadians,\n textKey,\n width,\n ])\n\n const classes = ['relative', className].filter(Boolean).join(' ')\n\n return (\n <div\n className={classes}\n style={{ position: style?.position ?? 'relative', ...style }}\n {...rest}\n >\n {children}\n {watermark && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{\n zIndex,\n backgroundImage: `url(${watermark.url})`,\n backgroundRepeat: 'repeat',\n backgroundSize: `${watermark.width}px ${watermark.height}px`,\n backgroundPosition: `${offsetX}px ${offsetY}px`,\n }}\n />\n )}\n </div>\n )\n}\n\nWatermark.displayName = 'Watermark'\n"],"names":["DEFAULT_CONTENT","DEFAULT_OPACITY","hexWithOpacity","hex","opacity","alpha","getFontSettings","font","resolvedColor","fontSize","Watermark","children","className","style","content","image","width","height","gap","offset","rotate","zIndex","rest","watermark","setWatermark","useState","gapX","gapY","offsetX","offsetY","colors","useTheme","textLines","useMemo","fontSettings","rotationInRadians","textKey","useEffect","cancelled","ratio","tileWidth","tileHeight","canvas","ctx","commitWatermark","url","drawText","lineHeight","startY","line","index","img","handleLoad","handleError","classes","jsxs","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"Watermark.js","sources":["../../src/components/Watermark.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react'\nimport { useTheme } from '../hooks/useTheme'\n\nexport type WatermarkGap = [number, number]\nexport type WatermarkOffset = [number, number]\n\nexport interface WatermarkFontOptions {\n /** Text color for watermark content */\n color?: string\n /** Font size in pixels */\n fontSize?: number\n /** Font weight for watermark text */\n fontWeight?: number | 'normal' | 'bold' | 'bolder' | 'lighter'\n /** Font style for watermark text */\n fontStyle?: 'normal' | 'italic' | 'oblique'\n /** Font family for watermark text */\n fontFamily?: string\n /** Line height in pixels for multi-line content */\n lineHeight?: number\n}\n\nexport interface WatermarkProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'content'> {\n /** Text to render inside the watermark; falls back to \"asterui\" */\n content?: string | string[]\n /** Image source (URL or base64) to render instead of text */\n image?: string\n /** Width of a single watermark tile in pixels */\n width?: number\n /** Height of a single watermark tile in pixels */\n height?: number\n /** Horizontal/vertical gap between watermarks in pixels */\n gap?: WatermarkGap\n /** Offset for the first watermark tile from the top-left corner */\n offset?: WatermarkOffset\n /** Rotation angle in degrees */\n rotate?: number\n /** z-index for the overlay layer */\n zIndex?: number\n /** Font settings for text watermarks */\n font?: WatermarkFontOptions\n /** Content to protect with the watermark */\n children?: React.ReactNode\n 'data-testid'?: string\n}\n\ntype WatermarkImage = {\n url: string\n width: number\n height: number\n}\n\nconst DEFAULT_CONTENT = 'asterui'\nconst DEFAULT_OPACITY = 0.22\n\n// Add opacity to a hex color (returns #rrggbbaa format)\nfunction hexWithOpacity(hex: string, opacity: number): string {\n const alpha = Math.round(opacity * 255).toString(16).padStart(2, '0')\n return hex + alpha\n}\n\nconst getFontSettings = (font: WatermarkFontOptions | undefined, resolvedColor: string) => {\n const fontSize = font?.fontSize ?? 16\n\n return {\n color: resolvedColor,\n fontSize,\n fontWeight: font?.fontWeight ?? 600,\n fontStyle: font?.fontStyle ?? 'normal',\n fontFamily: font?.fontFamily ?? 'sans-serif',\n lineHeight: font?.lineHeight ?? fontSize * 1.2,\n }\n}\n\nexport const Watermark: React.FC<WatermarkProps> = ({\n children,\n className = '',\n style,\n content,\n image,\n width = 120,\n height = 64,\n gap,\n offset,\n rotate = -22,\n zIndex = 1000,\n font,\n 'data-testid': testId,\n ...rest\n}) => {\n const [watermark, setWatermark] = useState<WatermarkImage | null>(null)\n\n const gapX = gap?.[0] ?? 120\n const gapY = gap?.[1] ?? 120\n const offsetX = offset?.[0] ?? gapX / 2\n const offsetY = offset?.[1] ?? gapY / 2\n const { colors } = useTheme()\n const textLines = useMemo(\n () =>\n typeof content === 'string'\n ? [content]\n : Array.isArray(content)\n ? content\n : [DEFAULT_CONTENT],\n [content]\n )\n // Use provided color or theme foreground with opacity\n const resolvedColor = font?.color ?? hexWithOpacity(colors.foreground, DEFAULT_OPACITY)\n const fontSettings = useMemo(\n () => getFontSettings(font, resolvedColor),\n [font, resolvedColor]\n )\n const rotationInRadians = (Math.PI / 180) * rotate\n const textKey = textLines.join('|')\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n let cancelled = false\n const ratio = window.devicePixelRatio || 1\n const tileWidth = width + gapX\n const tileHeight = height + gapY\n const canvas = document.createElement('canvas')\n canvas.width = tileWidth * ratio\n canvas.height = tileHeight * ratio\n const ctx = canvas.getContext('2d')\n\n if (!ctx) return\n\n const commitWatermark = () => {\n const url = canvas.toDataURL()\n if (!cancelled) {\n setWatermark({ url, width: tileWidth, height: tileHeight })\n }\n }\n\n const drawText = () => {\n ctx.save()\n ctx.translate((gapX / 2 + width / 2) * ratio, (gapY / 2 + height / 2) * ratio)\n ctx.rotate(rotationInRadians)\n ctx.fillStyle = fontSettings.color\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.font = `${fontSettings.fontStyle} normal ${fontSettings.fontWeight} ${fontSettings.fontSize * ratio}px ${fontSettings.fontFamily}`\n\n const lineHeight = fontSettings.lineHeight * ratio\n const startY = -((textLines.length - 1) * lineHeight) / 2\n\n textLines.forEach((line, index) => {\n ctx.fillText(line, 0, startY + index * lineHeight)\n })\n\n ctx.restore()\n }\n\n if (image) {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.referrerPolicy = 'no-referrer'\n\n const handleLoad = () => {\n ctx.save()\n ctx.translate((gapX / 2 + width / 2) * ratio, (gapY / 2 + height / 2) * ratio)\n ctx.rotate(rotationInRadians)\n ctx.drawImage(\n img,\n (-width / 2) * ratio,\n (-height / 2) * ratio,\n width * ratio,\n height * ratio\n )\n ctx.restore()\n commitWatermark()\n }\n\n const handleError = () => {\n if (!cancelled) setWatermark(null)\n }\n\n img.addEventListener('load', handleLoad)\n img.addEventListener('error', handleError)\n img.src = image\n\n return () => {\n cancelled = true\n img.removeEventListener('load', handleLoad)\n img.removeEventListener('error', handleError)\n }\n } else {\n drawText()\n commitWatermark()\n }\n\n return () => {\n cancelled = true\n }\n }, [\n fontSettings,\n gapX,\n gapY,\n height,\n image,\n rotationInRadians,\n textKey,\n width,\n ])\n\n const classes = ['relative', className].filter(Boolean).join(' ')\n\n const getTestId = (suffix: string) => (testId ? `${testId}-${suffix}` : undefined)\n\n return (\n <div\n className={classes}\n style={{ position: style?.position ?? 'relative', ...style }}\n data-testid={testId}\n {...rest}\n >\n {children}\n {watermark && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0\"\n style={{\n zIndex,\n backgroundImage: `url(${watermark.url})`,\n backgroundRepeat: 'repeat',\n backgroundSize: `${watermark.width}px ${watermark.height}px`,\n backgroundPosition: `${offsetX}px ${offsetY}px`,\n }}\n data-testid={getTestId('overlay')}\n />\n )}\n </div>\n )\n}\n\nWatermark.displayName = 'Watermark'\n"],"names":["DEFAULT_CONTENT","DEFAULT_OPACITY","hexWithOpacity","hex","opacity","alpha","getFontSettings","font","resolvedColor","fontSize","Watermark","children","className","style","content","image","width","height","gap","offset","rotate","zIndex","testId","rest","watermark","setWatermark","useState","gapX","gapY","offsetX","offsetY","colors","useTheme","textLines","useMemo","fontSettings","rotationInRadians","textKey","useEffect","cancelled","ratio","tileWidth","tileHeight","canvas","ctx","commitWatermark","url","drawText","lineHeight","startY","line","index","img","handleLoad","handleError","classes","getTestId","suffix","jsxs","jsx"],"mappings":"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"}
@@ -29,6 +29,7 @@ export interface WeekCalendarProps<T extends CalendarEvent = CalendarEvent> exte
29
29
  startHour?: number;
30
30
  /** End hour for the time grid (0-23) */
31
31
  endHour?: number;
32
+ 'data-testid'?: string;
32
33
  }
33
34
  export declare const WeekCalendar: <T extends CalendarEvent = CalendarEvent>(props: WeekCalendarProps<T> & {
34
35
  ref?: React.ForwardedRef<HTMLDivElement>;
@@ -1,6 +1,6 @@
1
- import { jsxs as d, jsx as i } from "react/jsx-runtime";
2
- import { forwardRef as L, useRef as M, useEffect as R, useMemo as C } from "react";
3
- const F = {
1
+ import { jsxs as m, jsx as d } from "react/jsx-runtime";
2
+ import { forwardRef as C, useRef as k, useEffect as F, useMemo as _ } from "react";
3
+ const J = {
4
4
  locale: "en",
5
5
  daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
6
6
  monthsLong: [
@@ -22,91 +22,95 @@ const F = {
22
22
  const t = s.getHours();
23
23
  return `${t === 0 ? 12 : t > 12 ? t - 12 : t}:00 ${t < 12 ? "AM" : "PM"}`.replace(" ", "").toLowerCase().replace(":00", "");
24
24
  }
25
- }, $ = (s) => _(s, /* @__PURE__ */ new Date()), _ = (s, t) => {
26
- const n = new Date(s), c = new Date(t);
27
- return n.setHours(0, 0, 0, 0), c.setHours(0, 0, 0, 0), c.getTime() === n.getTime();
28
- }, k = (s) => {
25
+ }, N = (s) => O(s, /* @__PURE__ */ new Date()), O = (s, t) => {
26
+ const n = new Date(s), i = new Date(t);
27
+ return n.setHours(0, 0, 0, 0), i.setHours(0, 0, 0, 0), i.getTime() === n.getTime();
28
+ }, T = (s) => {
29
29
  const t = /* @__PURE__ */ new Date(), n = new Date(s);
30
30
  return t.setHours(0, 0, 0, 0), n.setHours(0, 0, 0, 0), n < t;
31
- }, J = (s) => {
32
- const t = new Date(s), n = t.getDay(), c = t.getDate() - n;
33
- return new Date(t.setDate(c));
34
- }, O = (s, t) => {
31
+ }, P = (s) => {
32
+ const t = new Date(s), n = t.getDay(), i = t.getDate() - n;
33
+ return new Date(t.setDate(i));
34
+ }, z = (s, t) => {
35
35
  const n = new Date(s);
36
36
  return n.setDate(n.getDate() + t), n;
37
- }, u = (s, t) => {
38
- const n = s.getDate(), c = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][s.getDay()];
39
- return t === "YYYY-MM-DD" ? s.toISOString().split("T")[0] : t === "ddd" ? c : t === "D" ? n.toString() : s.toISOString();
40
- }, P = L(
37
+ }, f = (s, t) => {
38
+ const n = s.getDate(), i = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][s.getDay()];
39
+ return t === "YYYY-MM-DD" ? s.toISOString().split("T")[0] : t === "ddd" ? i : t === "D" ? n.toString() : s.toISOString();
40
+ }, q = C(
41
41
  ({
42
42
  date: s = /* @__PURE__ */ new Date(),
43
43
  events: t = [],
44
- locale: n = F,
45
- onEventClick: c,
46
- onDayClick: N,
47
- onSelectSlot: x,
48
- allowPastInteraction: m = !1,
49
- fitContainer: f = !1,
50
- startHour: y = 9,
51
- endHour: Y = 17,
52
- className: T = "",
53
- ...S
54
- }, E) => {
55
- const g = M(null), D = M(null);
56
- R(() => {
44
+ locale: n = J,
45
+ onEventClick: i,
46
+ onDayClick: Y,
47
+ onSelectSlot: w,
48
+ allowPastInteraction: b = !1,
49
+ fitContainer: p = !1,
50
+ startHour: v = 9,
51
+ endHour: S = 17,
52
+ className: E = "",
53
+ "data-testid": D,
54
+ ...H
55
+ }, W) => {
56
+ const x = k(null), y = k(null);
57
+ F(() => {
57
58
  const e = () => {
58
- if (g.current && D.current) {
59
- const r = g.current, o = D.current, l = r.offsetWidth - r.clientWidth;
60
- o.style.paddingRight = `${l}px`;
59
+ if (x.current && y.current) {
60
+ const r = x.current, o = y.current, c = r.offsetWidth - r.clientWidth;
61
+ o.style.paddingRight = `${c}px`;
61
62
  }
62
63
  };
63
64
  return e(), window.addEventListener("resize", e), () => window.removeEventListener("resize", e);
64
65
  }, []);
65
- const H = J(s), w = Array.from({ length: 7 }, (e, r) => O(H, r)), W = C(() => {
66
+ const A = P(s), $ = Array.from({ length: 7 }, (e, r) => z(A, r)), l = (e) => D ? `${D}-${e}` : void 0, j = _(() => {
66
67
  const e = {};
67
68
  return t.forEach((r) => {
68
- const o = u(r.date, "YYYY-MM-DD");
69
+ const o = f(r.date, "YYYY-MM-DD");
69
70
  e[o] || (e[o] = []), e[o].push(r);
70
71
  }), e;
71
- }, [t]), v = Array.from({ length: Y - y + 1 }, (e, r) => r + y), A = (e) => n.formatTime ? n.formatTime(new Date(2e3, 0, 1, e, 0)) : `${e === 0 ? 12 : e > 12 ? e - 12 : e}:00 ${e < 12 ? "AM" : "PM"}`, j = (e, r) => (W[e] || []).filter((l) => l.date.getHours() === r);
72
- return /* @__PURE__ */ d(
72
+ }, [t]), M = Array.from({ length: S - v + 1 }, (e, r) => r + v), L = (e) => n.formatTime ? n.formatTime(new Date(2e3, 0, 1, e, 0)) : `${e === 0 ? 12 : e > 12 ? e - 12 : e}:00 ${e < 12 ? "AM" : "PM"}`, R = (e, r) => (j[e] || []).filter((c) => c.date.getHours() === r);
73
+ return /* @__PURE__ */ m(
73
74
  "div",
74
75
  {
75
- ref: E,
76
- className: `flex h-full flex-col overflow-hidden border-b border-base-200 bg-base-100 ${T}`,
77
- ...S,
76
+ ref: W,
77
+ className: `flex h-full flex-col overflow-hidden border-b border-base-200 bg-base-100 ${E}`,
78
+ "data-testid": D,
79
+ ...H,
78
80
  children: [
79
- /* @__PURE__ */ d(
81
+ /* @__PURE__ */ m(
80
82
  "div",
81
83
  {
82
- ref: D,
84
+ ref: y,
83
85
  className: "grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 bg-base-100",
86
+ "data-testid": l("header"),
84
87
  children: [
85
- /* @__PURE__ */ i("div", { className: "week-calendar-time-column" }),
86
- w.map((e) => {
87
- const r = k(e), o = $(e);
88
- return /* @__PURE__ */ d(
88
+ /* @__PURE__ */ d("div", { className: "week-calendar-time-column" }),
89
+ $.map((e) => {
90
+ const r = T(e), o = N(e), c = f(e, "YYYY-MM-DD");
91
+ return /* @__PURE__ */ m(
89
92
  "div",
90
93
  {
91
94
  className: `
92
95
  cursor-pointer px-2 py-0.5 text-center transition-colors hover:bg-primary/5
93
- ${r && !m ? "cursor-not-allowed" : ""}
96
+ ${r && !b ? "cursor-not-allowed" : ""}
94
97
  `,
98
+ "data-testid": l(`header-day-${c}`),
95
99
  onClick: () => {
96
- r && !m || N?.(e);
100
+ r && !b || Y?.(e);
97
101
  },
98
102
  children: [
99
- /* @__PURE__ */ i(
103
+ /* @__PURE__ */ d(
100
104
  "div",
101
105
  {
102
106
  className: `
103
107
  text-xs font-medium uppercase
104
108
  ${r ? "text-base-content/40" : "text-base-content/60"}
105
109
  `,
106
- children: u(e, "ddd")
110
+ children: f(e, "ddd")
107
111
  }
108
112
  ),
109
- /* @__PURE__ */ i(
113
+ /* @__PURE__ */ d(
110
114
  "div",
111
115
  {
112
116
  className: `
@@ -114,49 +118,59 @@ const F = {
114
118
  ${o ? "font-bold text-primary" : ""}
115
119
  ${r && !o ? "text-base-content/40" : "text-base-content"}
116
120
  `,
117
- children: u(e, "D")
121
+ children: f(e, "D")
118
122
  }
119
123
  )
120
124
  ]
121
125
  },
122
- u(e, "YYYY-MM-DD")
126
+ c
123
127
  );
124
128
  })
125
129
  ]
126
130
  }
127
131
  ),
128
- /* @__PURE__ */ i(
132
+ /* @__PURE__ */ d(
129
133
  "div",
130
134
  {
131
- ref: g,
132
- className: f ? "grid flex-1" : "flex-1 overflow-y-auto",
133
- style: f ? { gridTemplateRows: `repeat(${v.length}, 1fr)` } : void 0,
134
- children: v.map((e) => /* @__PURE__ */ d(
135
+ ref: x,
136
+ className: p ? "grid flex-1" : "flex-1 overflow-y-auto",
137
+ style: p ? { gridTemplateRows: `repeat(${M.length}, 1fr)` } : void 0,
138
+ "data-testid": l("grid"),
139
+ children: M.map((e) => /* @__PURE__ */ m(
135
140
  "div",
136
141
  {
137
- className: `grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 last:border-b-0 ${f ? "min-h-10" : "h-20"}`,
142
+ className: `grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 last:border-b-0 ${p ? "min-h-10" : "h-20"}`,
143
+ "data-testid": l(`row-${e}`),
138
144
  children: [
139
- /* @__PURE__ */ i("div", { className: "flex items-start justify-end border-l border-r border-base-200 bg-base-200/50 p-2 pt-1 text-xs text-base-content/50", children: A(e) }),
140
- w.map((r) => {
141
- const o = u(r, "YYYY-MM-DD"), l = j(o, e), h = k(r) && !$(r);
142
- return /* @__PURE__ */ i(
145
+ /* @__PURE__ */ d(
146
+ "div",
147
+ {
148
+ className: "flex items-start justify-end border-l border-r border-base-200 bg-base-200/50 p-2 pt-1 text-xs text-base-content/50",
149
+ "data-testid": l(`time-${e}`),
150
+ children: L(e)
151
+ }
152
+ ),
153
+ $.map((r) => {
154
+ const o = f(r, "YYYY-MM-DD"), c = R(o, e), h = T(r) && !N(r);
155
+ return /* @__PURE__ */ d(
143
156
  "div",
144
157
  {
145
158
  className: `
146
159
  relative flex cursor-pointer flex-col justify-start overflow-y-auto border-r border-base-200 p-1 last:border-r-0
147
160
  hover:bg-primary/5
148
- ${f ? "" : "h-20"}
149
- ${h && !m ? "cursor-not-allowed hover:cursor-not-allowed" : ""}
161
+ ${p ? "" : "h-20"}
162
+ ${h && !b ? "cursor-not-allowed hover:cursor-not-allowed" : ""}
150
163
  `,
164
+ "data-testid": l(`cell-${o}-${e}`),
151
165
  onClick: (a) => {
152
- if (!(h && !m) && x && (a.target === a.currentTarget || a.target.classList.contains("week-calendar-time-cell"))) {
153
- const b = new Date(r);
154
- b.setHours(e, 0, 0, 0);
155
- const p = new Date(r);
156
- p.setHours(e + 1, 0, 0, 0), x({ start: b, end: p });
166
+ if (!(h && !b) && w && (a.target === a.currentTarget || a.target.classList.contains("week-calendar-time-cell"))) {
167
+ const u = new Date(r);
168
+ u.setHours(e, 0, 0, 0);
169
+ const g = new Date(r);
170
+ g.setHours(e + 1, 0, 0, 0), w({ start: u, end: g });
157
171
  }
158
172
  },
159
- children: l.map((a, b) => /* @__PURE__ */ d(
173
+ children: c.map((a, u) => /* @__PURE__ */ m(
160
174
  "div",
161
175
  {
162
176
  className: `
@@ -166,21 +180,22 @@ const F = {
166
180
  `,
167
181
  style: a.style,
168
182
  title: a.title,
169
- onClick: (p) => {
170
- p.stopPropagation(), c?.(a);
183
+ "data-testid": l(`event-${o}-${e}-${u}`),
184
+ onClick: (g) => {
185
+ g.stopPropagation(), i?.(a);
171
186
  },
172
187
  children: [
173
- /* @__PURE__ */ i(
188
+ /* @__PURE__ */ d(
174
189
  "div",
175
190
  {
176
191
  className: "mr-1.5 inline-block h-2 w-2 shrink-0 rounded-full",
177
192
  style: { backgroundColor: a.color || "#bfbfbf" }
178
193
  }
179
194
  ),
180
- /* @__PURE__ */ i("div", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: a.title })
195
+ /* @__PURE__ */ d("div", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children: a.title })
181
196
  ]
182
197
  },
183
- b
198
+ u
184
199
  ))
185
200
  },
186
201
  `${o}-${e}`
@@ -197,8 +212,8 @@ const F = {
197
212
  );
198
213
  }
199
214
  );
200
- P.displayName = "WeekCalendar";
215
+ q.displayName = "WeekCalendar";
201
216
  export {
202
- P as WeekCalendar
217
+ q as WeekCalendar
203
218
  };
204
219
  //# sourceMappingURL=WeekCalendar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WeekCalendar.js","sources":["../../src/components/WeekCalendar.tsx"],"sourcesContent":["import React, { useMemo, useRef, useEffect, forwardRef } from 'react'\n\n// DaisyUI classes\n// (No DaisyUI classes used in this component)\n\n// Types (shared with MonthCalendar)\nexport type CalendarEvent = {\n date: Date\n title: string\n color: string\n strikethrough?: boolean\n style?: React.CSSProperties\n}\n\nexport type CalendarLocale = {\n locale: string\n daysShort: string[]\n monthsLong: string[]\n moreText: string\n formatTime?: (date: Date) => string\n}\n\n// Default English locale\nconst defaultLocale: CalendarLocale = {\n locale: 'en',\n daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n monthsLong: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ],\n moreText: 'more',\n formatTime: (date: Date): string => {\n const hour = date.getHours()\n const formatted = `${hour === 0 ? 12 : hour > 12 ? hour - 12 : hour}:00 ${hour < 12 ? 'AM' : 'PM'}`\n return formatted.replace(' ', '').toLowerCase().replace(':00', '')\n },\n}\n\n// Utility functions\nconst isToday = (date: Date) => isEqual(date, new Date())\n\nconst isEqual = (a: Date, b: Date) => {\n const acopy = new Date(a)\n const bcopy = new Date(b)\n acopy.setHours(0, 0, 0, 0)\n bcopy.setHours(0, 0, 0, 0)\n return bcopy.getTime() === acopy.getTime()\n}\n\nconst isPastDate = (date: Date) => {\n const today = new Date()\n const checkDate = new Date(date)\n today.setHours(0, 0, 0, 0)\n checkDate.setHours(0, 0, 0, 0)\n return checkDate < today\n}\n\nconst getWeekStart = (date: Date): Date => {\n const d = new Date(date)\n const day = d.getDay()\n const diff = d.getDate() - day\n return new Date(d.setDate(diff))\n}\n\nconst addDays = (date: Date, days: number): Date => {\n const result = new Date(date)\n result.setDate(result.getDate() + days)\n return result\n}\n\nconst formatDate = (date: Date, format: string): string => {\n const day = date.getDate()\n const dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()]\n\n if (format === 'YYYY-MM-DD') {\n return date.toISOString().split('T')[0]\n }\n if (format === 'ddd') {\n return dayName\n }\n if (format === 'D') {\n return day.toString()\n }\n return date.toISOString()\n}\n\nexport interface WeekCalendarProps<T extends CalendarEvent = CalendarEvent>\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n date?: Date\n events?: T[]\n onEventClick?: (event: T) => void\n onDayClick?: (date: Date) => void\n onSelectSlot?: (slotInfo: { start: Date; end: Date }) => void\n locale?: CalendarLocale\n allowPastInteraction?: boolean\n fitContainer?: boolean\n /** Start hour for the time grid (0-23) */\n startHour?: number\n /** End hour for the time grid (0-23) */\n endHour?: number\n}\n\nexport const WeekCalendar = forwardRef<HTMLDivElement, WeekCalendarProps>(\n <T extends CalendarEvent>(\n {\n date = new Date(),\n events = [],\n locale = defaultLocale,\n onEventClick,\n onDayClick,\n onSelectSlot,\n allowPastInteraction = false,\n fitContainer = false,\n startHour = 9,\n endHour = 17,\n className = '',\n ...rest\n }: WeekCalendarProps<T>,\n ref: React.ForwardedRef<HTMLDivElement>\n ) => {\n const bodyRef = useRef<HTMLDivElement>(null)\n const headerRef = useRef<HTMLDivElement>(null)\n\n // Adjust header padding to account for scrollbar\n useEffect(() => {\n const adjustScrollbar = () => {\n if (bodyRef.current && headerRef.current) {\n const bodyElement = bodyRef.current\n const headerElement = headerRef.current\n const scrollbarWidth = bodyElement.offsetWidth - bodyElement.clientWidth\n headerElement.style.paddingRight = `${scrollbarWidth}px`\n }\n }\n\n adjustScrollbar()\n window.addEventListener('resize', adjustScrollbar)\n return () => window.removeEventListener('resize', adjustScrollbar)\n }, [])\n\n\n const weekStart = getWeekStart(date)\n const weekDays = Array.from({ length: 7 }, (_, i) => addDays(weekStart, i))\n\n // Group events by day\n const eventsByDay = useMemo(() => {\n const grouped: Record<string, T[]> = {}\n events.forEach((event) => {\n const eventDate = formatDate(event.date, 'YYYY-MM-DD')\n if (!grouped[eventDate]) {\n grouped[eventDate] = []\n }\n grouped[eventDate].push(event as T)\n })\n return grouped\n }, [events])\n\n // Time slots from startHour to endHour\n const timeSlots = Array.from({ length: endHour - startHour + 1 }, (_, i) => i + startHour)\n\n const formatHour = (hour: number) => {\n if (locale.formatTime) {\n return locale.formatTime(new Date(2000, 0, 1, hour, 0))\n }\n return `${hour === 0 ? 12 : hour > 12 ? hour - 12 : hour}:00 ${hour < 12 ? 'AM' : 'PM'}`\n }\n\n const getEventsForDayAndHour = (dayStr: string, hour: number) => {\n const dayEvents = eventsByDay[dayStr] || []\n return dayEvents.filter((event) => {\n const eventHour = event.date.getHours()\n return eventHour === hour\n })\n }\n\n return (\n <div\n ref={ref}\n className={`flex h-full flex-col overflow-hidden border-b border-base-200 bg-base-100 ${className}`}\n {...rest}\n >\n {/* Header with days */}\n <div\n ref={headerRef}\n className=\"grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 bg-base-100\"\n >\n <div className=\"week-calendar-time-column\" />\n {weekDays.map((day) => {\n const isPast = isPastDate(day)\n const isTodayDate = isToday(day)\n\n return (\n <div\n key={formatDate(day, 'YYYY-MM-DD')}\n className={`\n cursor-pointer px-2 py-0.5 text-center transition-colors hover:bg-primary/5\n ${isPast && !allowPastInteraction ? 'cursor-not-allowed' : ''}\n `}\n onClick={() => {\n if (isPast && !allowPastInteraction) {\n return\n }\n onDayClick?.(day)\n }}\n >\n <div\n className={`\n text-xs font-medium uppercase\n ${isPast ? 'text-base-content/40' : 'text-base-content/60'}\n `}\n >\n {formatDate(day, 'ddd')}\n </div>\n <div\n className={`\n mx-auto flex items-center justify-center text-xs font-medium transition-all\n ${isTodayDate ? 'font-bold text-primary' : ''}\n ${isPast && !isTodayDate ? 'text-base-content/40' : 'text-base-content'}\n `}\n >\n {formatDate(day, 'D')}\n </div>\n </div>\n )\n })}\n </div>\n\n {/* Time grid */}\n <div\n ref={bodyRef}\n className={fitContainer ? 'grid flex-1' : 'flex-1 overflow-y-auto'}\n style={fitContainer ? { gridTemplateRows: `repeat(${timeSlots.length}, 1fr)` } : undefined}\n >\n {timeSlots.map((hour) => (\n <div\n key={hour}\n className={`grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 last:border-b-0 ${fitContainer ? 'min-h-10' : 'h-20'}`}\n >\n {/* Time label */}\n <div className=\"flex items-start justify-end border-l border-r border-base-200 bg-base-200/50 p-2 pt-1 text-xs text-base-content/50\">\n {formatHour(hour)}\n </div>\n\n {/* Day cells */}\n {weekDays.map((day) => {\n const dayStr = formatDate(day, 'YYYY-MM-DD')\n const hourEvents = getEventsForDayAndHour(dayStr, hour)\n const isPast = isPastDate(day) && !isToday(day)\n\n return (\n <div\n key={`${dayStr}-${hour}`}\n className={`\n relative flex cursor-pointer flex-col justify-start overflow-y-auto border-r border-base-200 p-1 last:border-r-0\n hover:bg-primary/5\n ${fitContainer ? '' : 'h-20'}\n ${isPast && !allowPastInteraction ? 'cursor-not-allowed hover:cursor-not-allowed' : ''}\n `}\n onClick={(e) => {\n if (isPast && !allowPastInteraction) {\n return\n }\n\n if (\n onSelectSlot &&\n (e.target === e.currentTarget ||\n (e.target as HTMLElement).classList.contains('week-calendar-time-cell'))\n ) {\n const start = new Date(day)\n start.setHours(hour, 0, 0, 0)\n\n const end = new Date(day)\n end.setHours(hour + 1, 0, 0, 0)\n\n onSelectSlot({ start, end })\n }\n }}\n >\n {hourEvents.map((event, idx) => (\n <div\n key={idx}\n className={`\n mb-px flex shrink-0 cursor-pointer items-center rounded px-1 py-0.5 text-xs leading-none\n text-base-content transition-colors hover:bg-base-content/5 last:mb-0\n ${event.strikethrough ? 'line-through' : ''}\n `}\n style={event.style}\n title={event.title}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n >\n <div\n className=\"mr-1.5 inline-block h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: event.color || '#bfbfbf' }}\n />\n <div className=\"min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">\n {event.title}\n </div>\n </div>\n ))}\n </div>\n )\n })}\n </div>\n ))}\n </div>\n </div>\n )\n }\n) as <T extends CalendarEvent = CalendarEvent>(\n props: WeekCalendarProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }\n) => React.ReactElement\n\n;(WeekCalendar as React.FC).displayName = 'WeekCalendar'\n"],"names":["defaultLocale","date","hour","isToday","isEqual","a","b","acopy","bcopy","isPastDate","today","checkDate","getWeekStart","d","day","diff","addDays","days","result","formatDate","format","dayName","WeekCalendar","forwardRef","events","locale","onEventClick","onDayClick","onSelectSlot","allowPastInteraction","fitContainer","startHour","endHour","className","rest","ref","bodyRef","useRef","headerRef","useEffect","adjustScrollbar","bodyElement","headerElement","scrollbarWidth","weekStart","weekDays","_","i","eventsByDay","useMemo","grouped","event","eventDate","timeSlots","formatHour","getEventsForDayAndHour","dayStr","jsxs","jsx","isPast","isTodayDate","hourEvents","e","start","end","idx"],"mappings":"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"}
1
+ {"version":3,"file":"WeekCalendar.js","sources":["../../src/components/WeekCalendar.tsx"],"sourcesContent":["import React, { useMemo, useRef, useEffect, forwardRef } from 'react'\n\n// DaisyUI classes\n// (No DaisyUI classes used in this component)\n\n// Types (shared with MonthCalendar)\nexport type CalendarEvent = {\n date: Date\n title: string\n color: string\n strikethrough?: boolean\n style?: React.CSSProperties\n}\n\nexport type CalendarLocale = {\n locale: string\n daysShort: string[]\n monthsLong: string[]\n moreText: string\n formatTime?: (date: Date) => string\n}\n\n// Default English locale\nconst defaultLocale: CalendarLocale = {\n locale: 'en',\n daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],\n monthsLong: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ],\n moreText: 'more',\n formatTime: (date: Date): string => {\n const hour = date.getHours()\n const formatted = `${hour === 0 ? 12 : hour > 12 ? hour - 12 : hour}:00 ${hour < 12 ? 'AM' : 'PM'}`\n return formatted.replace(' ', '').toLowerCase().replace(':00', '')\n },\n}\n\n// Utility functions\nconst isToday = (date: Date) => isEqual(date, new Date())\n\nconst isEqual = (a: Date, b: Date) => {\n const acopy = new Date(a)\n const bcopy = new Date(b)\n acopy.setHours(0, 0, 0, 0)\n bcopy.setHours(0, 0, 0, 0)\n return bcopy.getTime() === acopy.getTime()\n}\n\nconst isPastDate = (date: Date) => {\n const today = new Date()\n const checkDate = new Date(date)\n today.setHours(0, 0, 0, 0)\n checkDate.setHours(0, 0, 0, 0)\n return checkDate < today\n}\n\nconst getWeekStart = (date: Date): Date => {\n const d = new Date(date)\n const day = d.getDay()\n const diff = d.getDate() - day\n return new Date(d.setDate(diff))\n}\n\nconst addDays = (date: Date, days: number): Date => {\n const result = new Date(date)\n result.setDate(result.getDate() + days)\n return result\n}\n\nconst formatDate = (date: Date, format: string): string => {\n const day = date.getDate()\n const dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()]\n\n if (format === 'YYYY-MM-DD') {\n return date.toISOString().split('T')[0]\n }\n if (format === 'ddd') {\n return dayName\n }\n if (format === 'D') {\n return day.toString()\n }\n return date.toISOString()\n}\n\nexport interface WeekCalendarProps<T extends CalendarEvent = CalendarEvent>\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n date?: Date\n events?: T[]\n onEventClick?: (event: T) => void\n onDayClick?: (date: Date) => void\n onSelectSlot?: (slotInfo: { start: Date; end: Date }) => void\n locale?: CalendarLocale\n allowPastInteraction?: boolean\n fitContainer?: boolean\n /** Start hour for the time grid (0-23) */\n startHour?: number\n /** End hour for the time grid (0-23) */\n endHour?: number\n 'data-testid'?: string\n}\n\nexport const WeekCalendar = forwardRef<HTMLDivElement, WeekCalendarProps>(\n <T extends CalendarEvent>(\n {\n date = new Date(),\n events = [],\n locale = defaultLocale,\n onEventClick,\n onDayClick,\n onSelectSlot,\n allowPastInteraction = false,\n fitContainer = false,\n startHour = 9,\n endHour = 17,\n className = '',\n 'data-testid': testId,\n ...rest\n }: WeekCalendarProps<T>,\n ref: React.ForwardedRef<HTMLDivElement>\n ) => {\n const bodyRef = useRef<HTMLDivElement>(null)\n const headerRef = useRef<HTMLDivElement>(null)\n\n // Adjust header padding to account for scrollbar\n useEffect(() => {\n const adjustScrollbar = () => {\n if (bodyRef.current && headerRef.current) {\n const bodyElement = bodyRef.current\n const headerElement = headerRef.current\n const scrollbarWidth = bodyElement.offsetWidth - bodyElement.clientWidth\n headerElement.style.paddingRight = `${scrollbarWidth}px`\n }\n }\n\n adjustScrollbar()\n window.addEventListener('resize', adjustScrollbar)\n return () => window.removeEventListener('resize', adjustScrollbar)\n }, [])\n\n\n const weekStart = getWeekStart(date)\n const weekDays = Array.from({ length: 7 }, (_, i) => addDays(weekStart, i))\n const getTestId = (suffix: string) => (testId ? `${testId}-${suffix}` : undefined)\n\n // Group events by day\n const eventsByDay = useMemo(() => {\n const grouped: Record<string, T[]> = {}\n events.forEach((event) => {\n const eventDate = formatDate(event.date, 'YYYY-MM-DD')\n if (!grouped[eventDate]) {\n grouped[eventDate] = []\n }\n grouped[eventDate].push(event as T)\n })\n return grouped\n }, [events])\n\n // Time slots from startHour to endHour\n const timeSlots = Array.from({ length: endHour - startHour + 1 }, (_, i) => i + startHour)\n\n const formatHour = (hour: number) => {\n if (locale.formatTime) {\n return locale.formatTime(new Date(2000, 0, 1, hour, 0))\n }\n return `${hour === 0 ? 12 : hour > 12 ? hour - 12 : hour}:00 ${hour < 12 ? 'AM' : 'PM'}`\n }\n\n const getEventsForDayAndHour = (dayStr: string, hour: number) => {\n const dayEvents = eventsByDay[dayStr] || []\n return dayEvents.filter((event) => {\n const eventHour = event.date.getHours()\n return eventHour === hour\n })\n }\n\n return (\n <div\n ref={ref}\n className={`flex h-full flex-col overflow-hidden border-b border-base-200 bg-base-100 ${className}`}\n data-testid={testId}\n {...rest}\n >\n {/* Header with days */}\n <div\n ref={headerRef}\n className=\"grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 bg-base-100\"\n data-testid={getTestId('header')}\n >\n <div className=\"week-calendar-time-column\" />\n {weekDays.map((day) => {\n const isPast = isPastDate(day)\n const isTodayDate = isToday(day)\n const dayKey = formatDate(day, 'YYYY-MM-DD')\n\n return (\n <div\n key={dayKey}\n className={`\n cursor-pointer px-2 py-0.5 text-center transition-colors hover:bg-primary/5\n ${isPast && !allowPastInteraction ? 'cursor-not-allowed' : ''}\n `}\n data-testid={getTestId(`header-day-${dayKey}`)}\n onClick={() => {\n if (isPast && !allowPastInteraction) {\n return\n }\n onDayClick?.(day)\n }}\n >\n <div\n className={`\n text-xs font-medium uppercase\n ${isPast ? 'text-base-content/40' : 'text-base-content/60'}\n `}\n >\n {formatDate(day, 'ddd')}\n </div>\n <div\n className={`\n mx-auto flex items-center justify-center text-xs font-medium transition-all\n ${isTodayDate ? 'font-bold text-primary' : ''}\n ${isPast && !isTodayDate ? 'text-base-content/40' : 'text-base-content'}\n `}\n >\n {formatDate(day, 'D')}\n </div>\n </div>\n )\n })}\n </div>\n\n {/* Time grid */}\n <div\n ref={bodyRef}\n className={fitContainer ? 'grid flex-1' : 'flex-1 overflow-y-auto'}\n style={fitContainer ? { gridTemplateRows: `repeat(${timeSlots.length}, 1fr)` } : undefined}\n data-testid={getTestId('grid')}\n >\n {timeSlots.map((hour) => (\n <div\n key={hour}\n className={`grid grid-cols-[80px_repeat(7,1fr)] border-b border-base-200 last:border-b-0 ${fitContainer ? 'min-h-10' : 'h-20'}`}\n data-testid={getTestId(`row-${hour}`)}\n >\n {/* Time label */}\n <div\n className=\"flex items-start justify-end border-l border-r border-base-200 bg-base-200/50 p-2 pt-1 text-xs text-base-content/50\"\n data-testid={getTestId(`time-${hour}`)}\n >\n {formatHour(hour)}\n </div>\n\n {/* Day cells */}\n {weekDays.map((day) => {\n const dayStr = formatDate(day, 'YYYY-MM-DD')\n const hourEvents = getEventsForDayAndHour(dayStr, hour)\n const isPast = isPastDate(day) && !isToday(day)\n\n return (\n <div\n key={`${dayStr}-${hour}`}\n className={`\n relative flex cursor-pointer flex-col justify-start overflow-y-auto border-r border-base-200 p-1 last:border-r-0\n hover:bg-primary/5\n ${fitContainer ? '' : 'h-20'}\n ${isPast && !allowPastInteraction ? 'cursor-not-allowed hover:cursor-not-allowed' : ''}\n `}\n data-testid={getTestId(`cell-${dayStr}-${hour}`)}\n onClick={(e) => {\n if (isPast && !allowPastInteraction) {\n return\n }\n\n if (\n onSelectSlot &&\n (e.target === e.currentTarget ||\n (e.target as HTMLElement).classList.contains('week-calendar-time-cell'))\n ) {\n const start = new Date(day)\n start.setHours(hour, 0, 0, 0)\n\n const end = new Date(day)\n end.setHours(hour + 1, 0, 0, 0)\n\n onSelectSlot({ start, end })\n }\n }}\n >\n {hourEvents.map((event, idx) => (\n <div\n key={idx}\n className={`\n mb-px flex shrink-0 cursor-pointer items-center rounded px-1 py-0.5 text-xs leading-none\n text-base-content transition-colors hover:bg-base-content/5 last:mb-0\n ${event.strikethrough ? 'line-through' : ''}\n `}\n style={event.style}\n title={event.title}\n data-testid={getTestId(`event-${dayStr}-${hour}-${idx}`)}\n onClick={(e) => {\n e.stopPropagation()\n onEventClick?.(event)\n }}\n >\n <div\n className=\"mr-1.5 inline-block h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: event.color || '#bfbfbf' }}\n />\n <div className=\"min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap\">\n {event.title}\n </div>\n </div>\n ))}\n </div>\n )\n })}\n </div>\n ))}\n </div>\n </div>\n )\n }\n) as <T extends CalendarEvent = CalendarEvent>(\n props: WeekCalendarProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }\n) => React.ReactElement\n\n;(WeekCalendar as React.FC).displayName = 'WeekCalendar'\n"],"names":["defaultLocale","date","hour","isToday","isEqual","a","b","acopy","bcopy","isPastDate","today","checkDate","getWeekStart","d","day","diff","addDays","days","result","formatDate","format","dayName","WeekCalendar","forwardRef","events","locale","onEventClick","onDayClick","onSelectSlot","allowPastInteraction","fitContainer","startHour","endHour","className","testId","rest","ref","bodyRef","useRef","headerRef","useEffect","adjustScrollbar","bodyElement","headerElement","scrollbarWidth","weekStart","weekDays","_","i","getTestId","suffix","eventsByDay","useMemo","grouped","event","eventDate","timeSlots","formatHour","getEventsForDayAndHour","dayStr","jsxs","jsx","isPast","isTodayDate","dayKey","hourEvents","e","start","end","idx"],"mappings":"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"}