@malilion/block-ui-react 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/components/display/Avatar/Avatar.d.ts +7 -0
  2. package/dist/components/display/Avatar/Avatar.d.ts.map +1 -0
  3. package/dist/components/display/Avatar/Avatar.js +53 -0
  4. package/dist/components/display/Avatar/Avatar.js.map +1 -0
  5. package/dist/components/display/Avatar/Avatar.module.js +17 -0
  6. package/dist/components/display/Avatar/Avatar.module.js.map +1 -0
  7. package/dist/components/display/Avatar/Avatar.types.d.ts +18 -0
  8. package/dist/components/display/Avatar/Avatar.types.d.ts.map +1 -0
  9. package/dist/components/display/Avatar/Avatar.types.js +11 -0
  10. package/dist/components/display/Avatar/Avatar.types.js.map +1 -0
  11. package/dist/components/display/Avatar/Avatar.utils.d.ts +7 -0
  12. package/dist/components/display/Avatar/Avatar.utils.d.ts.map +1 -0
  13. package/dist/components/display/Avatar/Avatar.utils.js +28 -0
  14. package/dist/components/display/Avatar/Avatar.utils.js.map +1 -0
  15. package/dist/components/display/Avatar/index.d.ts +5 -0
  16. package/dist/components/display/Avatar/index.d.ts.map +1 -0
  17. package/dist/components/display/index.d.ts +1 -0
  18. package/dist/components/display/index.d.ts.map +1 -1
  19. package/dist/components/feedback/Drawer/Drawer.d.ts +7 -0
  20. package/dist/components/feedback/Drawer/Drawer.d.ts.map +1 -0
  21. package/dist/components/feedback/Drawer/Drawer.js +78 -0
  22. package/dist/components/feedback/Drawer/Drawer.js.map +1 -0
  23. package/dist/components/feedback/Drawer/Drawer.module.js +25 -0
  24. package/dist/components/feedback/Drawer/Drawer.module.js.map +1 -0
  25. package/dist/components/feedback/Drawer/Drawer.types.d.ts +21 -0
  26. package/dist/components/feedback/Drawer/Drawer.types.d.ts.map +1 -0
  27. package/dist/components/feedback/Drawer/index.d.ts +3 -0
  28. package/dist/components/feedback/Drawer/index.d.ts.map +1 -0
  29. package/dist/components/feedback/EmptyState/EmptyState.d.ts +4 -0
  30. package/dist/components/feedback/EmptyState/EmptyState.d.ts.map +1 -0
  31. package/dist/components/feedback/EmptyState/EmptyState.js +35 -0
  32. package/dist/components/feedback/EmptyState/EmptyState.js.map +1 -0
  33. package/dist/components/feedback/EmptyState/EmptyState.module.js +17 -0
  34. package/dist/components/feedback/EmptyState/EmptyState.module.js.map +1 -0
  35. package/dist/components/feedback/EmptyState/EmptyState.types.d.ts +14 -0
  36. package/dist/components/feedback/EmptyState/EmptyState.types.d.ts.map +1 -0
  37. package/dist/components/feedback/EmptyState/index.d.ts +3 -0
  38. package/dist/components/feedback/EmptyState/index.d.ts.map +1 -0
  39. package/dist/components/feedback/Modal/BlockModal.d.ts.map +1 -1
  40. package/dist/components/feedback/Modal/BlockModal.js +3 -12
  41. package/dist/components/feedback/Modal/BlockModal.js.map +1 -1
  42. package/dist/components/feedback/Skeleton/Skeleton.d.ts +7 -0
  43. package/dist/components/feedback/Skeleton/Skeleton.d.ts.map +1 -0
  44. package/dist/components/feedback/Skeleton/Skeleton.js +33 -0
  45. package/dist/components/feedback/Skeleton/Skeleton.js.map +1 -0
  46. package/dist/components/feedback/Skeleton/Skeleton.module.js +12 -0
  47. package/dist/components/feedback/Skeleton/Skeleton.module.js.map +1 -0
  48. package/dist/components/feedback/Skeleton/Skeleton.types.d.ts +14 -0
  49. package/dist/components/feedback/Skeleton/Skeleton.types.d.ts.map +1 -0
  50. package/dist/components/feedback/Skeleton/Skeleton.types.js +11 -0
  51. package/dist/components/feedback/Skeleton/Skeleton.types.js.map +1 -0
  52. package/dist/components/feedback/Skeleton/index.d.ts +4 -0
  53. package/dist/components/feedback/Skeleton/index.d.ts.map +1 -0
  54. package/dist/components/feedback/index.d.ts +3 -0
  55. package/dist/components/feedback/index.d.ts.map +1 -1
  56. package/dist/components/forms/NumberInput/NumberInput.d.ts +8 -0
  57. package/dist/components/forms/NumberInput/NumberInput.d.ts.map +1 -0
  58. package/dist/components/forms/NumberInput/NumberInput.js +122 -0
  59. package/dist/components/forms/NumberInput/NumberInput.js.map +1 -0
  60. package/dist/components/forms/NumberInput/NumberInput.module.js +13 -0
  61. package/dist/components/forms/NumberInput/NumberInput.module.js.map +1 -0
  62. package/dist/components/forms/NumberInput/NumberInput.types.d.ts +20 -0
  63. package/dist/components/forms/NumberInput/NumberInput.types.d.ts.map +1 -0
  64. package/dist/components/forms/NumberInput/NumberInput.utils.d.ts +11 -0
  65. package/dist/components/forms/NumberInput/NumberInput.utils.d.ts.map +1 -0
  66. package/dist/components/forms/NumberInput/NumberInput.utils.js +26 -0
  67. package/dist/components/forms/NumberInput/NumberInput.utils.js.map +1 -0
  68. package/dist/components/forms/NumberInput/index.d.ts +3 -0
  69. package/dist/components/forms/NumberInput/index.d.ts.map +1 -0
  70. package/dist/components/forms/index.d.ts +1 -0
  71. package/dist/components/forms/index.d.ts.map +1 -1
  72. package/dist/components/layout/Accordion/Accordion.d.ts +7 -0
  73. package/dist/components/layout/Accordion/Accordion.d.ts.map +1 -0
  74. package/dist/components/layout/Accordion/Accordion.js +95 -0
  75. package/dist/components/layout/Accordion/Accordion.js.map +1 -0
  76. package/dist/components/layout/Accordion/Accordion.module.js +23 -0
  77. package/dist/components/layout/Accordion/Accordion.module.js.map +1 -0
  78. package/dist/components/layout/Accordion/Accordion.types.d.ts +21 -0
  79. package/dist/components/layout/Accordion/Accordion.types.d.ts.map +1 -0
  80. package/dist/components/layout/Accordion/index.d.ts +3 -0
  81. package/dist/components/layout/Accordion/index.d.ts.map +1 -0
  82. package/dist/components/layout/index.d.ts +1 -0
  83. package/dist/components/layout/index.d.ts.map +1 -1
  84. package/dist/hooks/useScrollLock.d.ts +6 -0
  85. package/dist/hooks/useScrollLock.d.ts.map +1 -0
  86. package/dist/hooks/useScrollLock.js +26 -0
  87. package/dist/hooks/useScrollLock.js.map +1 -0
  88. package/dist/index.js +10 -1
  89. package/dist/styles.css +459 -0
  90. package/package.json +4 -4
@@ -0,0 +1,7 @@
1
+ import type { AvatarProps } from "./Avatar.types";
2
+ /**
3
+ * Square block avatar: a pixelated face image, or initials on a material
4
+ * colour picked from the name, with an optional presence dot.
5
+ */
6
+ export declare const Avatar: import("react").ForwardRefExoticComponent<AvatarProps & import("react").RefAttributes<HTMLSpanElement>>;
7
+ //# sourceMappingURL=Avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Avatar/Avatar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAKlD;;;GAGG;AACH,eAAO,MAAM,MAAM,yGAiCjB,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { cx } from "../../../utils/cx.js";
2
+ import Avatar_module_default from "./Avatar.module.js";
3
+ import { avatarMaterial, initials } from "./Avatar.utils.js";
4
+ import { forwardRef, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/display/Avatar/Avatar.tsx
7
+ var STATUS_TEXT = {
8
+ online: "online",
9
+ away: "away",
10
+ busy: "busy",
11
+ offline: "offline"
12
+ };
13
+ /**
14
+ * Square block avatar: a pixelated face image, or initials on a material
15
+ * colour picked from the name, with an optional presence dot.
16
+ */
17
+ var Avatar = forwardRef(function Avatar({ name, src, icon, size = "md", status, decorative = false, className, ...rest }, ref) {
18
+ const [failedSrc, setFailedSrc] = useState(void 0);
19
+ const showImage = src !== void 0 && src !== failedSrc;
20
+ const accessibleName = status ? `${name} (${STATUS_TEXT[status]})` : name;
21
+ return /* @__PURE__ */ jsxs("span", {
22
+ ref,
23
+ role: decorative ? void 0 : "img",
24
+ "aria-label": decorative ? void 0 : accessibleName,
25
+ "aria-hidden": decorative || void 0,
26
+ "data-size": size,
27
+ "data-material": avatarMaterial(name),
28
+ className: cx(Avatar_module_default.avatar, className),
29
+ ...rest,
30
+ children: [showImage ? /* @__PURE__ */ jsx("img", {
31
+ src,
32
+ alt: "",
33
+ className: Avatar_module_default.image,
34
+ onError: () => setFailedSrc(src)
35
+ }) : icon ? /* @__PURE__ */ jsx("span", {
36
+ className: Avatar_module_default.icon,
37
+ "aria-hidden": "true",
38
+ children: icon
39
+ }) : /* @__PURE__ */ jsx("span", {
40
+ className: Avatar_module_default.initials,
41
+ "aria-hidden": "true",
42
+ children: initials(name)
43
+ }), status ? /* @__PURE__ */ jsx("span", {
44
+ className: Avatar_module_default.status,
45
+ "data-status": status,
46
+ "aria-hidden": "true"
47
+ }) : null]
48
+ });
49
+ });
50
+ //#endregion
51
+ export { Avatar };
52
+
53
+ //# sourceMappingURL=Avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.js","names":["styles"],"sources":["../../../../src/components/display/Avatar/Avatar.tsx"],"sourcesContent":["import { forwardRef, useState } from \"react\";\nimport { cx } from \"../../../utils/cx\";\nimport styles from \"./Avatar.module.css\";\nimport type { AvatarProps } from \"./Avatar.types\";\nimport { avatarMaterial, initials } from \"./Avatar.utils\";\n\nconst STATUS_TEXT = { online: \"online\", away: \"away\", busy: \"busy\", offline: \"offline\" } as const;\n\n/**\n * Square block avatar: a pixelated face image, or initials on a material\n * colour picked from the name, with an optional presence dot.\n */\nexport const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(function Avatar(\n { name, src, icon, size = \"md\", status, decorative = false, className, ...rest },\n ref,\n) {\n const [failedSrc, setFailedSrc] = useState<string | undefined>(undefined);\n const showImage = src !== undefined && src !== failedSrc;\n const accessibleName = status ? `${name} (${STATUS_TEXT[status]})` : name;\n\n return (\n <span\n ref={ref}\n role={decorative ? undefined : \"img\"}\n aria-label={decorative ? undefined : accessibleName}\n aria-hidden={decorative || undefined}\n data-size={size}\n data-material={avatarMaterial(name)}\n className={cx(styles.avatar, className)}\n {...rest}\n >\n {showImage ? (\n <img src={src} alt=\"\" className={styles.image} onError={() => setFailedSrc(src)} />\n ) : icon ? (\n <span className={styles.icon} aria-hidden=\"true\">\n {icon}\n </span>\n ) : (\n <span className={styles.initials} aria-hidden=\"true\">\n {initials(name)}\n </span>\n )}\n {status ? <span className={styles.status} data-status={status} aria-hidden=\"true\" /> : null}\n </span>\n );\n});\n"],"mappings":";;;;;;AAMA,IAAM,cAAc;CAAE,QAAQ;CAAU,MAAM;CAAQ,MAAM;CAAQ,SAAS;AAAU;;;;;AAMvF,IAAa,SAAS,WAAyC,SAAS,OACtE,EAAE,MAAM,KAAK,MAAM,OAAO,MAAM,QAAQ,aAAa,OAAO,WAAW,GAAG,QAC1E,KACA;CACA,MAAM,CAAC,WAAW,gBAAgB,SAA6B,KAAA,CAAS;CACxE,MAAM,YAAY,QAAQ,KAAA,KAAa,QAAQ;CAC/C,MAAM,iBAAiB,SAAS,GAAG,KAAK,IAAI,YAAY,QAAQ,KAAK;CAErE,OACE,qBAAC,QAAD;EACO;EACL,MAAM,aAAa,KAAA,IAAY;EAC/B,cAAY,aAAa,KAAA,IAAY;EACrC,eAAa,cAAc,KAAA;EAC3B,aAAW;EACX,iBAAe,eAAe,IAAI;EAClC,WAAW,GAAGA,sBAAO,QAAQ,SAAS;EACtC,GAAI;EARN,UAAA,CAUG,YACC,oBAAC,OAAD;GAAU;GAAK,KAAI;GAAG,WAAWA,sBAAO;GAAO,eAAe,aAAa,GAAG;EAAI,CAAA,IAChF,OACF,oBAAC,QAAD;GAAM,WAAWA,sBAAO;GAAM,eAAY;GACvC,UAAA;EACG,CAAA,IAEN,oBAAC,QAAD;GAAM,WAAWA,sBAAO;GAAU,eAAY;GAC3C,UAAA,SAAS,IAAI;EACV,CAAA,GAEP,SAAS,oBAAC,QAAD;GAAM,WAAWA,sBAAO;GAAQ,eAAa;GAAQ,eAAY;EAAQ,CAAA,IAAI,IACnF;;AAEV,CAAC"}
@@ -0,0 +1,17 @@
1
+ //#region src/components/display/Avatar/Avatar.module.css
2
+ var avatar = "block-avatar-9s1vM";
3
+ var image = "block-image-RZELF";
4
+ var icon = "block-icon-mq-FE";
5
+ var initials = "block-initials-siD-X";
6
+ var status = "block-status-CalIQ";
7
+ var Avatar_module_default = {
8
+ avatar,
9
+ image,
10
+ icon,
11
+ initials,
12
+ status
13
+ };
14
+ //#endregion
15
+ export { avatar, Avatar_module_default as default, icon, image, initials, status };
16
+
17
+ //# sourceMappingURL=Avatar.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.module.js","names":[],"sources":["../../../../src/components/display/Avatar/Avatar.module.css"],"sourcesContent":[".avatar {\n --avatar-size: 32px;\n position: relative;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--avatar-size);\n height: var(--avatar-size);\n color: var(--block-mat-on);\n background-color: var(--block-mat);\n border: var(--block-border-width-thin) solid var(--block-black);\n box-shadow:\n inset 2px 2px 0 var(--block-mat-light),\n inset -2px -2px 0 var(--block-mat-dark);\n vertical-align: middle;\n}\n\n.avatar[data-size=\"sm\"] {\n --avatar-size: 24px;\n}\n\n.avatar[data-size=\"lg\"] {\n --avatar-size: 48px;\n}\n\n.avatar[data-size=\"xl\"] {\n --avatar-size: 64px;\n}\n\n.image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n image-rendering: pixelated;\n}\n\n.icon {\n display: inline-flex;\n width: 70%;\n height: 70%;\n}\n\n.icon > * {\n width: 100%;\n height: 100%;\n}\n\n.initials {\n font-family: var(--block-font-display);\n font-size: calc(var(--avatar-size) * 0.4);\n font-weight: var(--block-font-weight-bold);\n line-height: 1;\n text-shadow: var(--block-mat-text-shadow, none);\n}\n\n/* Presence dot, a quarter of the avatar, in the bottom-right corner. */\n.status {\n position: absolute;\n right: -3px;\n bottom: -3px;\n width: max(8px, calc(var(--avatar-size) * 0.3));\n height: max(8px, calc(var(--avatar-size) * 0.3));\n border: 2px solid var(--block-black);\n}\n\n.status[data-status=\"online\"] {\n background-color: var(--block-emerald-light);\n}\n\n.status[data-status=\"away\"] {\n background-color: var(--block-gold-light);\n}\n\n.status[data-status=\"busy\"] {\n background-color: var(--block-redstone-light);\n}\n\n.status[data-status=\"offline\"] {\n background-color: var(--block-stone);\n}\n"],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export declare const avatarStatuses: readonly ["online", "away", "busy", "offline"];
3
+ export type AvatarStatus = (typeof avatarStatuses)[number];
4
+ export interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
5
+ /** Player name: the accessible name and the source of the initials. */
6
+ name: string;
7
+ /** Skin / face image URL (rendered pixelated). Falls back to initials if it fails. */
8
+ src?: string;
9
+ /** Icon instead of initials when there is no image. */
10
+ icon?: ReactNode;
11
+ /** 24 / 32 / 48 / 64 px. @default "md" */
12
+ size?: "sm" | "md" | "lg" | "xl";
13
+ /** Presence dot in the corner. */
14
+ status?: AvatarStatus;
15
+ /** Hide from assistive technology when the name is already shown next to it. */
16
+ decorative?: boolean;
17
+ }
18
+ //# sourceMappingURL=Avatar.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.types.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Avatar/Avatar.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,eAAO,MAAM,cAAc,gDAAiD,CAAC;AAE7E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;IAClE,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACjC,kCAAkC;IAClC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
@@ -0,0 +1,11 @@
1
+ //#region src/components/display/Avatar/Avatar.types.ts
2
+ var avatarStatuses = [
3
+ "online",
4
+ "away",
5
+ "busy",
6
+ "offline"
7
+ ];
8
+ //#endregion
9
+ export { avatarStatuses };
10
+
11
+ //# sourceMappingURL=Avatar.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.types.js","names":[],"sources":["../../../../src/components/display/Avatar/Avatar.types.ts"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\n\nexport const avatarStatuses = [\"online\", \"away\", \"busy\", \"offline\"] as const;\n\nexport type AvatarStatus = (typeof avatarStatuses)[number];\n\nexport interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {\n /** Player name: the accessible name and the source of the initials. */\n name: string;\n /** Skin / face image URL (rendered pixelated). Falls back to initials if it fails. */\n src?: string;\n /** Icon instead of initials when there is no image. */\n icon?: ReactNode;\n /** 24 / 32 / 48 / 64 px. @default \"md\" */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n /** Presence dot in the corner. */\n status?: AvatarStatus;\n /** Hide from assistive technology when the name is already shown next to it. */\n decorative?: boolean;\n}\n"],"mappings":";AAEA,IAAa,iBAAiB;CAAC;CAAU;CAAQ;CAAQ;AAAS"}
@@ -0,0 +1,7 @@
1
+ /** Up to two letters: first letters of the first two words, or the first two characters. */
2
+ export declare function initials(name: string): string;
3
+ declare const MATERIALS: readonly ["grass", "diamond", "gold", "redstone", "amethyst", "emerald", "wood", "water"];
4
+ /** Stable block material for a name, so a player always gets the same colour. */
5
+ export declare function avatarMaterial(name: string): (typeof MATERIALS)[number];
6
+ export {};
7
+ //# sourceMappingURL=Avatar.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.utils.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Avatar/Avatar.utils.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS7C;AAED,QAAA,MAAM,SAAS,2FASL,CAAC;AAEX,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAIvE"}
@@ -0,0 +1,28 @@
1
+ //#region src/components/display/Avatar/Avatar.utils.ts
2
+ /** Up to two letters: first letters of the first two words, or the first two characters. */
3
+ function initials(name) {
4
+ const words = name.replace(/[_\-.]+/g, " ").trim().split(/\s+/).filter(Boolean);
5
+ if (words.length === 0) return "?";
6
+ if (words.length === 1) return (words[0] ?? "").slice(0, 2).toUpperCase();
7
+ return `${words[0]?.[0] ?? ""}${words[1]?.[0] ?? ""}`.toUpperCase();
8
+ }
9
+ var MATERIALS = [
10
+ "grass",
11
+ "diamond",
12
+ "gold",
13
+ "redstone",
14
+ "amethyst",
15
+ "emerald",
16
+ "wood",
17
+ "water"
18
+ ];
19
+ /** Stable block material for a name, so a player always gets the same colour. */
20
+ function avatarMaterial(name) {
21
+ let hash = 0;
22
+ for (const char of name) hash = hash * 31 + char.charCodeAt(0) >>> 0;
23
+ return MATERIALS[hash % MATERIALS.length] ?? "grass";
24
+ }
25
+ //#endregion
26
+ export { avatarMaterial, initials };
27
+
28
+ //# sourceMappingURL=Avatar.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.utils.js","names":[],"sources":["../../../../src/components/display/Avatar/Avatar.utils.ts"],"sourcesContent":["/** Up to two letters: first letters of the first two words, or the first two characters. */\nexport function initials(name: string): string {\n const words = name\n .replace(/[_\\-.]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter(Boolean);\n if (words.length === 0) return \"?\";\n if (words.length === 1) return (words[0] ?? \"\").slice(0, 2).toUpperCase();\n return `${words[0]?.[0] ?? \"\"}${words[1]?.[0] ?? \"\"}`.toUpperCase();\n}\n\nconst MATERIALS = [\n \"grass\",\n \"diamond\",\n \"gold\",\n \"redstone\",\n \"amethyst\",\n \"emerald\",\n \"wood\",\n \"water\",\n] as const;\n\n/** Stable block material for a name, so a player always gets the same colour. */\nexport function avatarMaterial(name: string): (typeof MATERIALS)[number] {\n let hash = 0;\n for (const char of name) hash = (hash * 31 + char.charCodeAt(0)) >>> 0;\n return MATERIALS[hash % MATERIALS.length] ?? \"grass\";\n}\n"],"mappings":";;AACA,SAAgB,SAAS,MAAsB;CAC7C,MAAM,QAAQ,KACX,QAAQ,YAAY,GAAG,CAAC,CACxB,KAAK,CAAC,CACN,MAAM,KAAK,CAAC,CACZ,OAAO,OAAO;CACjB,IAAI,MAAM,WAAW,GAAG,OAAO;CAC/B,IAAI,MAAM,WAAW,GAAG,QAAQ,MAAM,MAAM,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY;CACxE,OAAO,GAAG,MAAM,EAAE,GAAG,MAAM,KAAK,MAAM,EAAE,GAAG,MAAM,KAAK,YAAY;AACpE;AAEA,IAAM,YAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,eAAe,MAA0C;CACvE,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,MAAM,OAAQ,OAAO,KAAK,KAAK,WAAW,CAAC,MAAO;CACrE,OAAO,UAAU,OAAO,UAAU,WAAW;AAC/C"}
@@ -0,0 +1,5 @@
1
+ export { Avatar } from "./Avatar";
2
+ export { avatarStatuses } from "./Avatar.types";
3
+ export { initials } from "./Avatar.utils";
4
+ export type { AvatarProps, AvatarStatus } from "./Avatar.types";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Avatar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
@@ -2,4 +2,5 @@ export * from "./BlockBadge";
2
2
  export * from "./BlockTooltip";
3
3
  export * from "./BlockTable";
4
4
  export * from "./SkillTree";
5
+ export * from "./Avatar";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { DrawerProps } from "./Drawer.types";
2
+ /**
3
+ * Panel that slides in from an edge (inventory, settings, mobile menu). Modal
4
+ * like `BlockModal`: focus trap, Escape, overlay click and focus restoration.
5
+ */
6
+ export declare const Drawer: import("react").ForwardRefExoticComponent<DrawerProps & import("react").RefAttributes<HTMLDivElement>>;
7
+ //# sourceMappingURL=Drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Drawer/Drawer.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,MAAM,wGAsEjB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { cx } from "../../../utils/cx.js";
2
+ import { usePortalContainer } from "../../../provider/context.js";
3
+ import { mergeRefs } from "../../../utils/refs.js";
4
+ import { useFocusTrap } from "../../../hooks/useFocusTrap.js";
5
+ import { useScrollLock } from "../../../hooks/useScrollLock.js";
6
+ import Drawer_module_default from "./Drawer.module.js";
7
+ import { forwardRef, useId, useRef } from "react";
8
+ import { createPortal } from "react-dom";
9
+ import { CloseIcon } from "@malilion/block-ui-icons";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/components/feedback/Drawer/Drawer.tsx
12
+ /**
13
+ * Panel that slides in from an edge (inventory, settings, mobile menu). Modal
14
+ * like `BlockModal`: focus trap, Escape, overlay click and focus restoration.
15
+ */
16
+ var Drawer = forwardRef(function Drawer({ open, onClose, title, children, footer, side = "right", size = "md", closeOnOverlayClick = true, closeOnEscape = true, initialFocusRef, className, ...rest }, ref) {
17
+ const container = usePortalContainer();
18
+ const panelRef = useRef(null);
19
+ const titleId = useId();
20
+ useFocusTrap(panelRef, open && container !== null, { initialFocus: initialFocusRef });
21
+ useScrollLock(open);
22
+ if (!open || !container) return null;
23
+ const handleKeyDown = (event) => {
24
+ if (event.key === "Escape" && closeOnEscape) {
25
+ event.stopPropagation();
26
+ onClose();
27
+ }
28
+ };
29
+ const handleOverlayClick = (event) => {
30
+ if (closeOnOverlayClick && event.target === event.currentTarget) onClose();
31
+ };
32
+ return createPortal(/* @__PURE__ */ jsx("div", {
33
+ role: "presentation",
34
+ className: Drawer_module_default.overlay,
35
+ "data-side": side,
36
+ onMouseDown: handleOverlayClick,
37
+ onKeyDown: handleKeyDown,
38
+ children: /* @__PURE__ */ jsxs("div", {
39
+ ref: mergeRefs(panelRef, ref),
40
+ role: "dialog",
41
+ "aria-modal": "true",
42
+ "aria-labelledby": titleId,
43
+ tabIndex: -1,
44
+ "data-side": side,
45
+ "data-size": size,
46
+ className: cx(Drawer_module_default.drawer, className),
47
+ ...rest,
48
+ children: [
49
+ /* @__PURE__ */ jsxs("div", {
50
+ className: Drawer_module_default.header,
51
+ children: [/* @__PURE__ */ jsx("h2", {
52
+ id: titleId,
53
+ className: Drawer_module_default.title,
54
+ children: title
55
+ }), /* @__PURE__ */ jsx("button", {
56
+ type: "button",
57
+ className: Drawer_module_default.close,
58
+ "aria-label": "Close",
59
+ onClick: onClose,
60
+ children: /* @__PURE__ */ jsx(CloseIcon, { size: 16 })
61
+ })]
62
+ }),
63
+ /* @__PURE__ */ jsx("div", {
64
+ className: Drawer_module_default.body,
65
+ children
66
+ }),
67
+ footer ? /* @__PURE__ */ jsx("div", {
68
+ className: Drawer_module_default.footer,
69
+ children: footer
70
+ }) : null
71
+ ]
72
+ })
73
+ }), container);
74
+ });
75
+ //#endregion
76
+ export { Drawer };
77
+
78
+ //# sourceMappingURL=Drawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.js","names":["styles"],"sources":["../../../../src/components/feedback/Drawer/Drawer.tsx"],"sourcesContent":["import { CloseIcon } from \"@malilion/block-ui-icons\";\nimport { forwardRef, useId, useRef, type KeyboardEvent, type MouseEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useFocusTrap } from \"../../../hooks/useFocusTrap\";\nimport { useScrollLock } from \"../../../hooks/useScrollLock\";\nimport { usePortalContainer } from \"../../../provider/context\";\nimport { cx } from \"../../../utils/cx\";\nimport { mergeRefs } from \"../../../utils/refs\";\nimport styles from \"./Drawer.module.css\";\nimport type { DrawerProps } from \"./Drawer.types\";\n\n/**\n * Panel that slides in from an edge (inventory, settings, mobile menu). Modal\n * like `BlockModal`: focus trap, Escape, overlay click and focus restoration.\n */\nexport const Drawer = forwardRef<HTMLDivElement, DrawerProps>(function Drawer(\n {\n open,\n onClose,\n title,\n children,\n footer,\n side = \"right\",\n size = \"md\",\n closeOnOverlayClick = true,\n closeOnEscape = true,\n initialFocusRef,\n className,\n ...rest\n },\n ref,\n) {\n const container = usePortalContainer();\n const panelRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n\n useFocusTrap(panelRef, open && container !== null, { initialFocus: initialFocusRef });\n useScrollLock(open);\n\n if (!open || !container) return null;\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && closeOnEscape) {\n event.stopPropagation();\n onClose();\n }\n };\n\n const handleOverlayClick = (event: MouseEvent<HTMLDivElement>) => {\n if (closeOnOverlayClick && event.target === event.currentTarget) onClose();\n };\n\n return createPortal(\n <div\n role=\"presentation\"\n className={styles.overlay}\n data-side={side}\n onMouseDown={handleOverlayClick}\n onKeyDown={handleKeyDown}\n >\n <div\n ref={mergeRefs(panelRef, ref)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n data-side={side}\n data-size={size}\n className={cx(styles.drawer, className)}\n {...rest}\n >\n <div className={styles.header}>\n <h2 id={titleId} className={styles.title}>\n {title}\n </h2>\n <button type=\"button\" className={styles.close} aria-label=\"Close\" onClick={onClose}>\n <CloseIcon size={16} />\n </button>\n </div>\n <div className={styles.body}>{children}</div>\n {footer ? <div className={styles.footer}>{footer}</div> : null}\n </div>\n </div>,\n container,\n );\n});\n"],"mappings":";;;;;;;;;;;;;;;AAeA,IAAa,SAAS,WAAwC,SAAS,OACrE,EACE,MACA,SACA,OACA,UACA,QACA,OAAO,SACP,OAAO,MACP,sBAAsB,MACtB,gBAAgB,MAChB,iBACA,WACA,GAAG,QAEL,KACA;CACA,MAAM,YAAY,mBAAmB;CACrC,MAAM,WAAW,OAAuB,IAAI;CAC5C,MAAM,UAAU,MAAM;CAEtB,aAAa,UAAU,QAAQ,cAAc,MAAM,EAAE,cAAc,gBAAgB,CAAC;CACpF,cAAc,IAAI;CAElB,IAAI,CAAC,QAAQ,CAAC,WAAW,OAAO;CAEhC,MAAM,iBAAiB,UAAyC;EAC9D,IAAI,MAAM,QAAQ,YAAY,eAAe;GAC3C,MAAM,gBAAgB;GACtB,QAAQ;EACV;CACF;CAEA,MAAM,sBAAsB,UAAsC;EAChE,IAAI,uBAAuB,MAAM,WAAW,MAAM,eAAe,QAAQ;CAC3E;CAEA,OAAO,aACL,oBAAC,OAAD;EACE,MAAK;EACL,WAAWA,sBAAO;EAClB,aAAW;EACX,aAAa;EACb,WAAW;EAEX,UAAA,qBAAC,OAAD;GACE,KAAK,UAAU,UAAU,GAAG;GAC5B,MAAK;GACL,cAAW;GACX,mBAAiB;GACjB,UAAU;GACV,aAAW;GACX,aAAW;GACX,WAAW,GAAGA,sBAAO,QAAQ,SAAS;GACtC,GAAI;GATN,UAAA;IAWE,qBAAC,OAAD;KAAK,WAAWA,sBAAO;KAAvB,UAAA,CACE,oBAAC,MAAD;MAAI,IAAI;MAAS,WAAWA,sBAAO;MAChC,UAAA;KACC,CAAA,GACJ,oBAAC,UAAD;MAAQ,MAAK;MAAS,WAAWA,sBAAO;MAAO,cAAW;MAAQ,SAAS;MACzE,UAAA,oBAAC,WAAD,EAAW,MAAM,GAAK,CAAA;KAChB,CAAA,CACL;;IACL,oBAAC,OAAD;KAAK,WAAWA,sBAAO;KAAO;IAAc,CAAA;IAC3C,SAAS,oBAAC,OAAD;KAAK,WAAWA,sBAAO;KAAS,UAAA;IAAY,CAAA,IAAI;GACvD;;CACF,CAAA,GACL,SACF;AACF,CAAC"}
@@ -0,0 +1,25 @@
1
+ //#region src/components/feedback/Drawer/Drawer.module.css
2
+ var overlay = "block-overlay-MaF41";
3
+ var drawer = "block-drawer-aWDC6";
4
+ var header = "block-header-FheCx";
5
+ var title = "block-title-4QE9I";
6
+ var close = "block-close-fdVrq";
7
+ var body = "block-body-aFN-w";
8
+ var footer = "block-footer-m9z0P";
9
+ var Drawer_module_default = {
10
+ overlay,
11
+ "block-drawer-fade": "block-block-drawer-fade-4rcmM",
12
+ drawer,
13
+ "block-drawer-in-right": "block-block-drawer-in-right-Krar9",
14
+ "block-drawer-in-left": "block-block-drawer-in-left-EnlSn",
15
+ "block-drawer-in-bottom": "block-block-drawer-in-bottom-yyZ8z",
16
+ header,
17
+ title,
18
+ close,
19
+ body,
20
+ footer
21
+ };
22
+ //#endregion
23
+ export { body, close, Drawer_module_default as default, drawer, footer, header, overlay, title };
24
+
25
+ //# sourceMappingURL=Drawer.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.module.js","names":[],"sources":["../../../../src/components/feedback/Drawer/Drawer.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n z-index: var(--block-z-modal);\n display: flex;\n justify-content: flex-end;\n background-color: var(--block-overlay);\n animation: block-drawer-fade var(--block-duration-fast) steps(3, end);\n}\n\n.overlay[data-side=\"left\"] {\n justify-content: flex-start;\n}\n\n.overlay[data-side=\"bottom\"] {\n flex-direction: column;\n justify-content: flex-end;\n}\n\n.drawer {\n --drawer-size: 360px;\n display: flex;\n flex-direction: column;\n width: min(var(--drawer-size), 100%);\n height: 100%;\n color: var(--block-text);\n background-color: var(--block-surface);\n background-image:\n linear-gradient(\n color-mix(in srgb, var(--block-surface) 88%, transparent),\n color-mix(in srgb, var(--block-surface) 88%, transparent)\n ),\n var(--block-texture);\n background-size:\n auto,\n 64px 64px;\n border-left: var(--block-border-width) solid var(--block-border);\n box-shadow: var(--block-shadow-bevel);\n outline: none;\n animation: block-drawer-in-right var(--block-duration-normal) steps(4, end);\n}\n\n.drawer[data-size=\"sm\"] {\n --drawer-size: 280px;\n}\n\n.drawer[data-size=\"lg\"] {\n --drawer-size: 520px;\n}\n\n.drawer[data-side=\"left\"] {\n border-left: 0;\n border-right: var(--block-border-width) solid var(--block-border);\n animation-name: block-drawer-in-left;\n}\n\n.drawer[data-side=\"bottom\"] {\n --drawer-size: 50dvh;\n width: 100%;\n height: min(var(--drawer-size), 100%);\n border-left: 0;\n border-top: var(--block-border-width) solid var(--block-border);\n animation-name: block-drawer-in-bottom;\n}\n\n.drawer[data-side=\"bottom\"][data-size=\"sm\"] {\n --drawer-size: 33dvh;\n}\n\n.drawer[data-side=\"bottom\"][data-size=\"lg\"] {\n --drawer-size: 80dvh;\n}\n\n.header {\n display: flex;\n align-items: center;\n gap: var(--block-space-2);\n margin: 3px 3px 0;\n padding: var(--block-space-2) var(--block-space-3);\n background-color: var(--block-surface-header);\n border-bottom: var(--block-border-width-thin) solid var(--block-border);\n}\n\n.title {\n flex: 1;\n margin: 0;\n font-family: var(--block-font-display);\n font-size: var(--block-font-size-lg);\n font-weight: var(--block-font-weight-bold);\n letter-spacing: var(--block-letter-spacing-wide);\n text-transform: uppercase;\n text-shadow: var(--block-shadow-text);\n}\n\n.close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n color: var(--block-text);\n background-color: var(--block-slot);\n border: var(--block-border-width-thin) solid var(--block-border);\n box-shadow: var(--block-shadow-inset);\n cursor: pointer;\n}\n\n.close:focus-visible {\n outline: 3px solid var(--block-focus);\n outline-offset: 2px;\n}\n\n.body {\n flex: 1;\n min-height: 0;\n padding: var(--block-space-4);\n overflow-y: auto;\n}\n\n.footer {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--block-space-2);\n padding: var(--block-space-3) var(--block-space-4);\n border-top: var(--block-border-width-thin) solid var(--block-border);\n}\n\n@keyframes block-drawer-fade {\n from {\n opacity: 0;\n }\n}\n\n@keyframes block-drawer-in-right {\n from {\n transform: translateX(100%);\n }\n}\n\n@keyframes block-drawer-in-left {\n from {\n transform: translateX(-100%);\n }\n}\n\n@keyframes block-drawer-in-bottom {\n from {\n transform: translateY(100%);\n }\n}\n"],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { HTMLAttributes, ReactNode, RefObject } from "react";
2
+ export interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
3
+ open: boolean;
4
+ /** Called on Escape, overlay click or the close button. */
5
+ onClose: () => void;
6
+ title: ReactNode;
7
+ children?: ReactNode;
8
+ /** Action row pinned to the bottom. */
9
+ footer?: ReactNode;
10
+ /** Edge the drawer slides from. @default "right" */
11
+ side?: "left" | "right" | "bottom";
12
+ /** Width (or height for `bottom`). @default "md" */
13
+ size?: "sm" | "md" | "lg";
14
+ /** @default true */
15
+ closeOnOverlayClick?: boolean;
16
+ /** @default true */
17
+ closeOnEscape?: boolean;
18
+ /** Element focused when the drawer opens. Defaults to the first focusable element. */
19
+ initialFocusRef?: RefObject<HTMLElement | null>;
20
+ }
21
+ //# sourceMappingURL=Drawer.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.types.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Drawer/Drawer.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAChF,IAAI,EAAE,OAAO,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACnC,oDAAoD;IACpD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,oBAAoB;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oBAAoB;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sFAAsF;IACtF,eAAe,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACjD"}
@@ -0,0 +1,3 @@
1
+ export { Drawer } from "./Drawer";
2
+ export type { DrawerProps } from "./Drawer.types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Drawer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { EmptyStateProps } from "./EmptyState.types";
2
+ /** Placeholder for an empty list or search: icon, title, description and an action. */
3
+ export declare const EmptyState: import("react").ForwardRefExoticComponent<EmptyStateProps & import("react").RefAttributes<HTMLDivElement>>;
4
+ //# sourceMappingURL=EmptyState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/EmptyState/EmptyState.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,uFAAuF;AACvF,eAAO,MAAM,UAAU,4GAcrB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { cx } from "../../../utils/cx.js";
2
+ import EmptyState_module_default from "./EmptyState.module.js";
3
+ import { createElement, forwardRef } from "react";
4
+ import { ChestIcon } from "@malilion/block-ui-icons";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/feedback/EmptyState/EmptyState.tsx
7
+ /** Placeholder for an empty list or search: icon, title, description and an action. */
8
+ var EmptyState = forwardRef(function EmptyState({ title, description, icon, action, headingLevel = 3, size = "md", className, ...rest }, ref) {
9
+ return /* @__PURE__ */ jsxs("div", {
10
+ ref,
11
+ "data-size": size,
12
+ className: cx(EmptyState_module_default.empty, className),
13
+ ...rest,
14
+ children: [
15
+ /* @__PURE__ */ jsx("span", {
16
+ className: EmptyState_module_default.icon,
17
+ "aria-hidden": "true",
18
+ children: icon ?? /* @__PURE__ */ jsx(ChestIcon, { size: size === "sm" ? 32 : 48 })
19
+ }),
20
+ createElement(`h${headingLevel}`, { className: EmptyState_module_default.title }, title),
21
+ description ? /* @__PURE__ */ jsx("p", {
22
+ className: EmptyState_module_default.description,
23
+ children: description
24
+ }) : null,
25
+ action ? /* @__PURE__ */ jsx("div", {
26
+ className: EmptyState_module_default.action,
27
+ children: action
28
+ }) : null
29
+ ]
30
+ });
31
+ });
32
+ //#endregion
33
+ export { EmptyState };
34
+
35
+ //# sourceMappingURL=EmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.js","names":["styles"],"sources":["../../../../src/components/feedback/EmptyState/EmptyState.tsx"],"sourcesContent":["import { ChestIcon } from \"@malilion/block-ui-icons\";\nimport { createElement, forwardRef } from \"react\";\nimport { cx } from \"../../../utils/cx\";\nimport styles from \"./EmptyState.module.css\";\nimport type { EmptyStateProps } from \"./EmptyState.types\";\n\n/** Placeholder for an empty list or search: icon, title, description and an action. */\nexport const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(function EmptyState(\n { title, description, icon, action, headingLevel = 3, size = \"md\", className, ...rest },\n ref,\n) {\n return (\n <div ref={ref} data-size={size} className={cx(styles.empty, className)} {...rest}>\n <span className={styles.icon} aria-hidden=\"true\">\n {icon ?? <ChestIcon size={size === \"sm\" ? 32 : 48} />}\n </span>\n {createElement(`h${headingLevel}`, { className: styles.title }, title)}\n {description ? <p className={styles.description}>{description}</p> : null}\n {action ? <div className={styles.action}>{action}</div> : null}\n </div>\n );\n});\n"],"mappings":";;;;;;;AAOA,IAAa,aAAa,WAA4C,SAAS,WAC7E,EAAE,OAAO,aAAa,MAAM,QAAQ,eAAe,GAAG,OAAO,MAAM,WAAW,GAAG,QACjF,KACA;CACA,OACE,qBAAC,OAAD;EAAU;EAAK,aAAW;EAAM,WAAW,GAAGA,0BAAO,OAAO,SAAS;EAAG,GAAI;EAA5E,UAAA;GACE,oBAAC,QAAD;IAAM,WAAWA,0BAAO;IAAM,eAAY;IACvC,UAAA,QAAQ,oBAAC,WAAD,EAAW,MAAM,SAAS,OAAO,KAAK,GAAK,CAAA;GAChD,CAAA;GACL,cAAc,IAAI,gBAAgB,EAAE,WAAWA,0BAAO,MAAM,GAAG,KAAK;GACpE,cAAc,oBAAC,KAAD;IAAG,WAAWA,0BAAO;IAAc,UAAA;GAAe,CAAA,IAAI;GACpE,SAAS,oBAAC,OAAD;IAAK,WAAWA,0BAAO;IAAS,UAAA;GAAY,CAAA,IAAI;EACvD;;AAET,CAAC"}
@@ -0,0 +1,17 @@
1
+ //#region src/components/feedback/EmptyState/EmptyState.module.css
2
+ var empty = "block-empty-CypAE";
3
+ var icon = "block-icon-RT29d";
4
+ var title = "block-title-gsp4I";
5
+ var description = "block-description-es-JM";
6
+ var action = "block-action-TqLZE";
7
+ var EmptyState_module_default = {
8
+ empty,
9
+ icon,
10
+ title,
11
+ description,
12
+ action
13
+ };
14
+ //#endregion
15
+ export { action, EmptyState_module_default as default, description, empty, icon, title };
16
+
17
+ //# sourceMappingURL=EmptyState.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.module.js","names":[],"sources":["../../../../src/components/feedback/EmptyState/EmptyState.module.css"],"sourcesContent":[".empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--block-space-2);\n width: 100%;\n padding: var(--block-space-8) var(--block-space-4);\n text-align: center;\n color: var(--block-text);\n background-color: var(--block-slot);\n border: var(--block-border-width-thin) dashed var(--block-border);\n}\n\n.empty[data-size=\"sm\"] {\n padding: var(--block-space-4) var(--block-space-3);\n}\n\n.icon {\n display: inline-flex;\n opacity: 0.6;\n filter: grayscale(0.5);\n}\n\n.title {\n margin: 0;\n font-family: var(--block-font-display);\n font-size: var(--block-font-size-md);\n font-weight: var(--block-font-weight-bold);\n letter-spacing: var(--block-letter-spacing-wide);\n text-transform: uppercase;\n text-shadow: var(--block-shadow-text);\n}\n\n.empty[data-size=\"sm\"] .title {\n font-size: var(--block-font-size-sm);\n}\n\n.description {\n max-width: 42ch;\n margin: 0;\n font-size: var(--block-font-size-sm);\n color: var(--block-text-muted);\n}\n\n.action {\n margin-top: var(--block-space-2);\n}\n"],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
3
+ title: ReactNode;
4
+ description?: ReactNode;
5
+ /** Pixel icon above the title. Defaults to an empty chest. */
6
+ icon?: ReactNode;
7
+ /** Call to action, usually a `BlockButton`. */
8
+ action?: ReactNode;
9
+ /** Heading level of the title. @default 3 */
10
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
11
+ /** @default "md" */
12
+ size?: "sm" | "md";
13
+ }
14
+ //# sourceMappingURL=EmptyState.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.types.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/EmptyState/EmptyState.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvD,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACpF,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,oBAAoB;IACpB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACpB"}
@@ -0,0 +1,3 @@
1
+ export { EmptyState } from "./EmptyState";
2
+ export type { EmptyStateProps } from "./EmptyState.types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/EmptyState/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"BlockModal.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Modal/BlockModal.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI1D;;;GAGG;AACH,eAAO,MAAM,UAAU,4GAiGrB,CAAC"}
1
+ {"version":3,"file":"BlockModal.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Modal/BlockModal.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,UAAU,4GAwFrB,CAAC"}
@@ -2,13 +2,13 @@ import { cx } from "../../../utils/cx.js";
2
2
  import { usePortalContainer } from "../../../provider/context.js";
3
3
  import { mergeRefs } from "../../../utils/refs.js";
4
4
  import { useFocusTrap } from "../../../hooks/useFocusTrap.js";
5
+ import { useScrollLock } from "../../../hooks/useScrollLock.js";
5
6
  import BlockModal_module_default from "./BlockModal.module.js";
6
- import { forwardRef, useEffect, useId, useRef } from "react";
7
+ import { forwardRef, useId, useRef } from "react";
7
8
  import { createPortal } from "react-dom";
8
9
  import { CloseIcon } from "@malilion/block-ui-icons";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
10
11
  //#region src/components/feedback/Modal/BlockModal.tsx
11
- var openModals = 0;
12
12
  /**
13
13
  * Accessible modal dialog: focus trap, `Escape` to close, overlay, focus
14
14
  * restoration and `aria-modal` dialog semantics (PRD §45).
@@ -19,16 +19,7 @@ var BlockModal = forwardRef(function BlockModal({ open, onClose, title, descript
19
19
  const titleId = useId();
20
20
  const descriptionId = useId();
21
21
  useFocusTrap(dialogRef, open && container !== null, { initialFocus: initialFocusRef });
22
- useEffect(() => {
23
- if (!open) return void 0;
24
- openModals += 1;
25
- const previous = document.body.style.overflow;
26
- document.body.style.overflow = "hidden";
27
- return () => {
28
- openModals -= 1;
29
- if (openModals === 0) document.body.style.overflow = previous;
30
- };
31
- }, [open]);
22
+ useScrollLock(open);
32
23
  if (!open || !container) return null;
33
24
  const handleKeyDown = (event) => {
34
25
  if (event.key === "Escape" && closeOnEscape) {
@@ -1 +1 @@
1
- {"version":3,"file":"BlockModal.js","names":["styles"],"sources":["../../../../src/components/feedback/Modal/BlockModal.tsx"],"sourcesContent":["import { CloseIcon } from \"@malilion/block-ui-icons\";\nimport { forwardRef, useEffect, useId, useRef, type KeyboardEvent, type MouseEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useFocusTrap } from \"../../../hooks/useFocusTrap\";\nimport { usePortalContainer } from \"../../../provider/context\";\nimport { cx } from \"../../../utils/cx\";\nimport { mergeRefs } from \"../../../utils/refs\";\nimport styles from \"./BlockModal.module.css\";\nimport type { BlockModalProps } from \"./BlockModal.types\";\n\nlet openModals = 0;\n\n/**\n * Accessible modal dialog: focus trap, `Escape` to close, overlay, focus\n * restoration and `aria-modal` dialog semantics (PRD §45).\n */\nexport const BlockModal = forwardRef<HTMLDivElement, BlockModalProps>(function BlockModal(\n {\n open,\n onClose,\n title,\n description,\n children,\n footer,\n size = \"md\",\n closeOnOverlayClick = true,\n closeOnEscape = true,\n hideCloseButton = false,\n initialFocusRef,\n role = \"dialog\",\n icon,\n className,\n ...rest\n },\n ref,\n) {\n const container = usePortalContainer();\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const descriptionId = useId();\n\n useFocusTrap(dialogRef, open && container !== null, { initialFocus: initialFocusRef });\n\n useEffect(() => {\n if (!open) return undefined;\n openModals += 1;\n const previous = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n openModals -= 1;\n if (openModals === 0) document.body.style.overflow = previous;\n };\n }, [open]);\n\n if (!open || !container) return null;\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && closeOnEscape) {\n event.stopPropagation();\n onClose();\n }\n };\n\n const handleOverlayClick = (event: MouseEvent<HTMLDivElement>) => {\n if (closeOnOverlayClick && event.target === event.currentTarget) onClose();\n };\n\n return createPortal(\n <div\n role=\"presentation\"\n className={styles.overlay}\n onMouseDown={handleOverlayClick}\n onKeyDown={handleKeyDown}\n >\n <div\n ref={mergeRefs(dialogRef, ref)}\n role={role}\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n tabIndex={-1}\n data-size={size}\n className={cx(styles.dialog, className)}\n {...rest}\n >\n <div className={styles.header}>\n <h2 id={titleId} className={styles.title}>\n {title}\n </h2>\n {hideCloseButton ? null : (\n <button type=\"button\" className={styles.close} aria-label=\"Close\" onClick={onClose}>\n <CloseIcon size={16} />\n </button>\n )}\n </div>\n <div className={styles.body}>\n {icon ? (\n <div className={styles.icon} aria-hidden=\"true\">\n {icon}\n </div>\n ) : null}\n {description ? (\n <div id={descriptionId} className={styles.description}>\n {description}\n </div>\n ) : null}\n {children}\n </div>\n {footer ? <div className={styles.footer}>{footer}</div> : null}\n </div>\n </div>,\n container,\n );\n});\n"],"mappings":";;;;;;;;;;AAUA,IAAI,aAAa;;;;;AAMjB,IAAa,aAAa,WAA4C,SAAS,WAC7E,EACE,MACA,SACA,OACA,aACA,UACA,QACA,OAAO,MACP,sBAAsB,MACtB,gBAAgB,MAChB,kBAAkB,OAClB,iBACA,OAAO,UACP,MACA,WACA,GAAG,QAEL,KACA;CACA,MAAM,YAAY,mBAAmB;CACrC,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,UAAU,MAAM;CACtB,MAAM,gBAAgB,MAAM;CAE5B,aAAa,WAAW,QAAQ,cAAc,MAAM,EAAE,cAAc,gBAAgB,CAAC;CAErF,gBAAgB;EACd,IAAI,CAAC,MAAM,OAAO,KAAA;EAClB,cAAc;EACd,MAAM,WAAW,SAAS,KAAK,MAAM;EACrC,SAAS,KAAK,MAAM,WAAW;EAC/B,aAAa;GACX,cAAc;GACd,IAAI,eAAe,GAAG,SAAS,KAAK,MAAM,WAAW;EACvD;CACF,GAAG,CAAC,IAAI,CAAC;CAET,IAAI,CAAC,QAAQ,CAAC,WAAW,OAAO;CAEhC,MAAM,iBAAiB,UAAyC;EAC9D,IAAI,MAAM,QAAQ,YAAY,eAAe;GAC3C,MAAM,gBAAgB;GACtB,QAAQ;EACV;CACF;CAEA,MAAM,sBAAsB,UAAsC;EAChE,IAAI,uBAAuB,MAAM,WAAW,MAAM,eAAe,QAAQ;CAC3E;CAEA,OAAO,aACL,oBAAC,OAAD;EACE,MAAK;EACL,WAAWA,0BAAO;EAClB,aAAa;EACb,WAAW;EAEX,UAAA,qBAAC,OAAD;GACE,KAAK,UAAU,WAAW,GAAG;GACvB;GACN,cAAW;GACX,mBAAiB;GACjB,oBAAkB,cAAc,gBAAgB,KAAA;GAChD,UAAU;GACV,aAAW;GACX,WAAW,GAAGA,0BAAO,QAAQ,SAAS;GACtC,GAAI;GATN,UAAA;IAWE,qBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAvB,UAAA,CACE,oBAAC,MAAD;MAAI,IAAI;MAAS,WAAWA,0BAAO;MAChC,UAAA;KACC,CAAA,GACH,kBAAkB,OACjB,oBAAC,UAAD;MAAQ,MAAK;MAAS,WAAWA,0BAAO;MAAO,cAAW;MAAQ,SAAS;MACzE,UAAA,oBAAC,WAAD,EAAW,MAAM,GAAK,CAAA;KAChB,CAAA,CAEP;;IACL,qBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAvB,UAAA;MACG,OACC,oBAAC,OAAD;OAAK,WAAWA,0BAAO;OAAM,eAAY;OACtC,UAAA;MACE,CAAA,IACH;MACH,cACC,oBAAC,OAAD;OAAK,IAAI;OAAe,WAAWA,0BAAO;OACvC,UAAA;MACE,CAAA,IACH;MACH;KACE;;IACJ,SAAS,oBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAS,UAAA;IAAY,CAAA,IAAI;GACvD;;CACF,CAAA,GACL,SACF;AACF,CAAC"}
1
+ {"version":3,"file":"BlockModal.js","names":["styles"],"sources":["../../../../src/components/feedback/Modal/BlockModal.tsx"],"sourcesContent":["import { CloseIcon } from \"@malilion/block-ui-icons\";\nimport { forwardRef, useId, useRef, type KeyboardEvent, type MouseEvent } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useFocusTrap } from \"../../../hooks/useFocusTrap\";\nimport { useScrollLock } from \"../../../hooks/useScrollLock\";\nimport { usePortalContainer } from \"../../../provider/context\";\nimport { cx } from \"../../../utils/cx\";\nimport { mergeRefs } from \"../../../utils/refs\";\nimport styles from \"./BlockModal.module.css\";\nimport type { BlockModalProps } from \"./BlockModal.types\";\n\n/**\n * Accessible modal dialog: focus trap, `Escape` to close, overlay, focus\n * restoration and `aria-modal` dialog semantics (PRD §45).\n */\nexport const BlockModal = forwardRef<HTMLDivElement, BlockModalProps>(function BlockModal(\n {\n open,\n onClose,\n title,\n description,\n children,\n footer,\n size = \"md\",\n closeOnOverlayClick = true,\n closeOnEscape = true,\n hideCloseButton = false,\n initialFocusRef,\n role = \"dialog\",\n icon,\n className,\n ...rest\n },\n ref,\n) {\n const container = usePortalContainer();\n const dialogRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const descriptionId = useId();\n\n useFocusTrap(dialogRef, open && container !== null, { initialFocus: initialFocusRef });\n\n useScrollLock(open);\n\n if (!open || !container) return null;\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && closeOnEscape) {\n event.stopPropagation();\n onClose();\n }\n };\n\n const handleOverlayClick = (event: MouseEvent<HTMLDivElement>) => {\n if (closeOnOverlayClick && event.target === event.currentTarget) onClose();\n };\n\n return createPortal(\n <div\n role=\"presentation\"\n className={styles.overlay}\n onMouseDown={handleOverlayClick}\n onKeyDown={handleKeyDown}\n >\n <div\n ref={mergeRefs(dialogRef, ref)}\n role={role}\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n tabIndex={-1}\n data-size={size}\n className={cx(styles.dialog, className)}\n {...rest}\n >\n <div className={styles.header}>\n <h2 id={titleId} className={styles.title}>\n {title}\n </h2>\n {hideCloseButton ? null : (\n <button type=\"button\" className={styles.close} aria-label=\"Close\" onClick={onClose}>\n <CloseIcon size={16} />\n </button>\n )}\n </div>\n <div className={styles.body}>\n {icon ? (\n <div className={styles.icon} aria-hidden=\"true\">\n {icon}\n </div>\n ) : null}\n {description ? (\n <div id={descriptionId} className={styles.description}>\n {description}\n </div>\n ) : null}\n {children}\n </div>\n {footer ? <div className={styles.footer}>{footer}</div> : null}\n </div>\n </div>,\n container,\n );\n});\n"],"mappings":";;;;;;;;;;;;;;;AAeA,IAAa,aAAa,WAA4C,SAAS,WAC7E,EACE,MACA,SACA,OACA,aACA,UACA,QACA,OAAO,MACP,sBAAsB,MACtB,gBAAgB,MAChB,kBAAkB,OAClB,iBACA,OAAO,UACP,MACA,WACA,GAAG,QAEL,KACA;CACA,MAAM,YAAY,mBAAmB;CACrC,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,UAAU,MAAM;CACtB,MAAM,gBAAgB,MAAM;CAE5B,aAAa,WAAW,QAAQ,cAAc,MAAM,EAAE,cAAc,gBAAgB,CAAC;CAErF,cAAc,IAAI;CAElB,IAAI,CAAC,QAAQ,CAAC,WAAW,OAAO;CAEhC,MAAM,iBAAiB,UAAyC;EAC9D,IAAI,MAAM,QAAQ,YAAY,eAAe;GAC3C,MAAM,gBAAgB;GACtB,QAAQ;EACV;CACF;CAEA,MAAM,sBAAsB,UAAsC;EAChE,IAAI,uBAAuB,MAAM,WAAW,MAAM,eAAe,QAAQ;CAC3E;CAEA,OAAO,aACL,oBAAC,OAAD;EACE,MAAK;EACL,WAAWA,0BAAO;EAClB,aAAa;EACb,WAAW;EAEX,UAAA,qBAAC,OAAD;GACE,KAAK,UAAU,WAAW,GAAG;GACvB;GACN,cAAW;GACX,mBAAiB;GACjB,oBAAkB,cAAc,gBAAgB,KAAA;GAChD,UAAU;GACV,aAAW;GACX,WAAW,GAAGA,0BAAO,QAAQ,SAAS;GACtC,GAAI;GATN,UAAA;IAWE,qBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAvB,UAAA,CACE,oBAAC,MAAD;MAAI,IAAI;MAAS,WAAWA,0BAAO;MAChC,UAAA;KACC,CAAA,GACH,kBAAkB,OACjB,oBAAC,UAAD;MAAQ,MAAK;MAAS,WAAWA,0BAAO;MAAO,cAAW;MAAQ,SAAS;MACzE,UAAA,oBAAC,WAAD,EAAW,MAAM,GAAK,CAAA;KAChB,CAAA,CAEP;;IACL,qBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAvB,UAAA;MACG,OACC,oBAAC,OAAD;OAAK,WAAWA,0BAAO;OAAM,eAAY;OACtC,UAAA;MACE,CAAA,IACH;MACH,cACC,oBAAC,OAAD;OAAK,IAAI;OAAe,WAAWA,0BAAO;OACvC,UAAA;MACE,CAAA,IACH;MACH;KACE;;IACJ,SAAS,oBAAC,OAAD;KAAK,WAAWA,0BAAO;KAAS,UAAA;IAAY,CAAA,IAAI;GACvD;;CACF,CAAA,GACL,SACF;AACF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SkeletonProps } from "./Skeleton.types";
2
+ /**
3
+ * Pixel placeholder shown while content loads. Decorative (`aria-hidden`):
4
+ * mark the loading container with `aria-busy` and announce loading separately.
5
+ */
6
+ export declare const Skeleton: import("react").ForwardRefExoticComponent<SkeletonProps & import("react").RefAttributes<HTMLSpanElement>>;
7
+ //# sourceMappingURL=Skeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Skeleton/Skeleton.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,QAAQ,2GA6BnB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { cx } from "../../../utils/cx.js";
2
+ import Skeleton_module_default from "./Skeleton.module.js";
3
+ import { forwardRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/feedback/Skeleton/Skeleton.tsx
6
+ /**
7
+ * Pixel placeholder shown while content loads. Decorative (`aria-hidden`):
8
+ * mark the loading container with `aria-busy` and announce loading separately.
9
+ */
10
+ var Skeleton = forwardRef(function Skeleton({ variant = "text", lines = 1, width, height, className, style, ...rest }, ref) {
11
+ const sizing = {
12
+ ...width ? { "--block-skeleton-width": width } : null,
13
+ ...height ? { "--block-skeleton-height": height } : null,
14
+ ...style
15
+ };
16
+ const count = variant === "text" ? Math.max(1, Math.floor(lines)) : 1;
17
+ return /* @__PURE__ */ jsx("span", {
18
+ ref,
19
+ "aria-hidden": "true",
20
+ "data-variant": variant,
21
+ className: cx(Skeleton_module_default.skeleton, className),
22
+ style: sizing,
23
+ ...rest,
24
+ children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx("span", {
25
+ className: Skeleton_module_default.bone,
26
+ "data-last": count > 1 && index === count - 1 || void 0
27
+ }, index))
28
+ });
29
+ });
30
+ //#endregion
31
+ export { Skeleton };
32
+
33
+ //# sourceMappingURL=Skeleton.js.map