@gnome-ui/react 1.47.0 → 1.49.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.
- package/README.md +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.d.ts +16 -0
- package/dist/components/AvatarGroup/AvatarGroup.js +36 -0
- package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.css.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.css.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.css.js +13 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.css.js.map +1 -0
- package/dist/components/AvatarGroup/index.d.ts +2 -0
- package/dist/components/AvatarGroup.cjs +1 -0
- package/dist/components/AvatarGroup.d.ts +2 -0
- package/dist/components/AvatarGroup.js +2 -0
- package/dist/components/BottomSheet/BottomSheet.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.d.ts +3 -3
- package/dist/components/BottomSheet/BottomSheet.js +72 -31
- package/dist/components/BottomSheet/BottomSheet.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.css.cjs +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.css.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.css.js +13 -8
- package/dist/components/BottomSheet/BottomSheet.module.css.js.map +1 -1
- package/dist/components/EntryRow/EntryRow.module.css.cjs +1 -1
- package/dist/components/EntryRow/EntryRow.module.css.cjs.map +1 -1
- package/dist/components/EntryRow/EntryRow.module.css.js +10 -10
- package/dist/components/EntryRow/EntryRow.module.css.js.map +1 -1
- package/dist/components/Icon/Icon.cjs +1 -1
- package/dist/components/Icon/Icon.cjs.map +1 -1
- package/dist/components/Icon/Icon.d.ts +8 -1
- package/dist/components/Icon/Icon.js +22 -20
- package/dist/components/Icon/Icon.js.map +1 -1
- package/dist/components/Icon/Icon.module.css.cjs +2 -0
- package/dist/components/Icon/Icon.module.css.cjs.map +1 -0
- package/dist/components/Icon/Icon.module.css.js +14 -0
- package/dist/components/Icon/Icon.module.css.js.map +1 -0
- package/dist/components/Icon/index.d.ts +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.cjs +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.cjs.map +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.d.ts +11 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.js +136 -24
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.js.map +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.module.css.cjs +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.module.css.cjs.map +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.module.css.js +22 -10
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.module.css.js.map +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.cjs +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.cjs.map +1 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.d.ts +4 -1
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.js +7 -6
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.js.map +1 -1
- package/dist/components/InlineViewSwitcher/index.d.ts +1 -1
- package/dist/components/Modal/Modal.cjs +2 -0
- package/dist/components/Modal/Modal.cjs.map +1 -0
- package/dist/components/Modal/Modal.d.ts +40 -0
- package/dist/components/Modal/Modal.js +93 -0
- package/dist/components/Modal/Modal.js.map +1 -0
- package/dist/components/Modal/Modal.module.css.cjs +2 -0
- package/dist/components/Modal/Modal.module.css.cjs.map +1 -0
- package/dist/components/Modal/Modal.module.css.js +23 -0
- package/dist/components/Modal/Modal.module.css.js.map +1 -0
- package/dist/components/Modal/index.d.ts +2 -0
- package/dist/components/Modal.cjs +1 -0
- package/dist/components/Modal.d.ts +2 -0
- package/dist/components/Modal.js +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +95 -93
- package/dist/style.css +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -205,6 +205,7 @@ import { Button } from "@gnome-ui/react/components/Button";
|
|
|
205
205
|
| [`Text`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-text--docs) | 12 Adwaita type styles: large-title, title-1…4, heading, body, caption… |
|
|
206
206
|
| [`Icon`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-icon--docs) | Inline SVG icon. Accepts `@gnome-ui/icons` definitions, [`simple-icons`](https://simpleicons.org/) icons, or any `{ path }` object; inherits `currentColor` |
|
|
207
207
|
| [`Avatar`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-avatar--docs) | Circular user image with deterministic-color initials fallback |
|
|
208
|
+
| [`AvatarGroup`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-avatargroup--docs) | Overlapping stack of avatars with configurable max visible count and `+N` overflow indicator |
|
|
208
209
|
| [`AvatarRotator`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-avatarrotator--docs) | Single avatar surface that crossfades through multiple image sources |
|
|
209
210
|
| [`Badge`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-badge--docs) | Counter or status dot, optionally anchored over another element |
|
|
210
211
|
| [`StatusBadge`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-statusbadge--docs) | Pill-shaped text label for entity status — published, beta, new, etc.; 6 variants |
|
|
@@ -258,6 +259,7 @@ import { Button } from "@gnome-ui/react/components/Button";
|
|
|
258
259
|
|-----------|-------------|
|
|
259
260
|
| [`Toast`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-toast--docs) / `Toaster` | Non-blocking temporary notification with auto-dismiss, action, and queue support |
|
|
260
261
|
| [`Dialog`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-dialog--docs) | Blocking modal with title, body, focus trap, and configurable buttons |
|
|
262
|
+
| [`Modal`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-modal--docs) | Large overlay for rich content, forms, and settings; scrollable body, header bar with close button and optional primary/secondary actions |
|
|
261
263
|
| [`BottomSheet`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-bottomsheet--docs) | Slide-up panel from the bottom of the viewport with drag handle and optional title |
|
|
262
264
|
| [`Drawer`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-drawer--docs) | Slide-over panel that opens from the left or right with React content |
|
|
263
265
|
| [`Tooltip`](https://eljijuna.github.io/gnome-ui/?path=/docs/components-tooltip--docs) | Floating informational label on hover/focus with auto-flip positioning |
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../Avatar/Avatar.cjs"),t=require("./AvatarGroup.module.css.cjs");let n=require("react/jsx-runtime");var r=({avatars:r,max:i=5,size:a=`md`,className:o,"aria-label":s,...c})=>{let l=r.length>i?r.slice(0,i):r,u=r.length>i?r.length-i:0,d=r.map(e=>e.name).filter(Boolean).join(`, `);return(0,n.jsxs)(`span`,{role:`group`,"aria-label":s??(d?u>0?`${d} and ${u} more`:d:`Avatar group`),className:[t.default.group,t.default[a],o].filter(Boolean).join(` `),...c,children:[l.map((r,i)=>(0,n.jsx)(e.Avatar,{name:r.name,src:r.src,alt:r.alt??r.name,color:r.color,size:a,className:t.default.item},`${r.name??``}-${r.src??``}-${i}`)),u>0&&(0,n.jsx)(`span`,{"aria-label":`+${u} more`,className:[t.default.overflow,t.default[a]].filter(Boolean).join(` `),children:(0,n.jsxs)(`span`,{"aria-hidden":`true`,children:[`+`,u]})})]})};exports.AvatarGroup=r;
|
|
2
|
+
//# sourceMappingURL=AvatarGroup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarGroup.cjs","names":[],"sources":["../../../src/components/AvatarGroup/AvatarGroup.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\n\nimport { Avatar, type AvatarColor, type AvatarSize } from '../Avatar';\n\nimport styles from './AvatarGroup.module.css';\n\nexport interface AvatarGroupItem {\n name?: string;\n src?: string;\n alt?: string;\n color?: AvatarColor;\n}\n\nexport interface AvatarGroupProps extends HTMLAttributes<HTMLSpanElement> {\n avatars: AvatarGroupItem[];\n /** Max visible avatars before showing overflow chip. Defaults to `5`. */\n max?: number;\n /** Size applied to all avatars and the overflow chip. Defaults to `\"md\"`. */\n size?: AvatarSize;\n}\n\nexport const AvatarGroup = ({\n avatars,\n max = 5,\n size = 'md',\n className,\n 'aria-label': ariaLabel,\n ...props\n}: AvatarGroupProps) => {\n const visible = avatars.length > max ? avatars.slice(0, max) : avatars;\n const overflowCount = avatars.length > max ? avatars.length - max : 0;\n\n const allNames = avatars\n .map((a) => a.name)\n .filter(Boolean)\n .join(', ');\n\n const label =\n ariaLabel ??\n (allNames\n ? overflowCount > 0\n ? `${allNames} and ${overflowCount} more`\n : allNames\n : 'Avatar group');\n\n const classes = [styles.group, styles[size], className].filter(Boolean).join(' ');\n\n return (\n <span role=\"group\" aria-label={label} className={classes} {...props}>\n {visible.map((item, index) => (\n <Avatar\n key={`${item.name ?? ''}-${item.src ?? ''}-${index}`}\n name={item.name}\n src={item.src}\n alt={item.alt ?? item.name}\n color={item.color}\n size={size}\n className={styles.item}\n />\n ))}\n {overflowCount > 0 && (\n <span\n aria-label={`+${overflowCount} more`}\n className={[styles.overflow, styles[size]].filter(Boolean).join(' ')}\n >\n <span aria-hidden=\"true\">+{overflowCount}</span>\n </span>\n )}\n </span>\n );\n};\n"],"mappings":"qHAqBA,IAAa,GAAe,CAC1B,UACA,MAAM,EACN,OAAO,KACP,YACA,aAAc,EACd,GAAG,KACmB,CACtB,IAAM,EAAU,EAAQ,OAAS,EAAM,EAAQ,MAAM,EAAG,CAAG,EAAI,EACzD,EAAgB,EAAQ,OAAS,EAAM,EAAQ,OAAS,EAAM,EAE9D,EAAW,EACd,IAAK,GAAM,EAAE,IAAI,EACjB,OAAO,OAAO,EACd,KAAK,IAAI,EAYZ,OACE,EAAA,EAAA,MAAC,OAAD,CAAM,KAAK,QAAQ,aAVnB,IACC,EACG,EAAgB,EACd,GAAG,EAAS,OAAO,EAAc,OACjC,EACF,gBAKkC,UAHxB,CAAC,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAG1B,EAAS,GAAI,WAA9D,CACG,EAAQ,KAAK,EAAM,KAClB,EAAA,EAAA,KAAC,EAAA,OAAD,CAEE,KAAM,EAAK,KACX,IAAK,EAAK,IACV,IAAK,EAAK,KAAO,EAAK,KACtB,MAAO,EAAK,MACN,OACN,UAAW,EAAA,QAAO,IACnB,EAPM,GAAG,EAAK,MAAQ,GAAG,GAAG,EAAK,KAAO,GAAG,GAAG,GAO9C,CACF,EACA,EAAgB,IACf,EAAA,EAAA,KAAC,OAAD,CACE,aAAY,IAAI,EAAc,OAC9B,UAAW,CAAC,EAAA,QAAO,SAAU,EAAA,QAAO,EAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,YAEnE,EAAA,EAAA,MAAC,OAAD,CAAM,cAAY,gBAAlB,CAAyB,IAAE,CAAoB,GAC3C,CAAA,CAEJ,GAEV"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { AvatarColor, AvatarSize } from '../Avatar';
|
|
3
|
+
export interface AvatarGroupItem {
|
|
4
|
+
name?: string;
|
|
5
|
+
src?: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
color?: AvatarColor;
|
|
8
|
+
}
|
|
9
|
+
export interface AvatarGroupProps extends HTMLAttributes<HTMLSpanElement> {
|
|
10
|
+
avatars: AvatarGroupItem[];
|
|
11
|
+
/** Max visible avatars before showing overflow chip. Defaults to `5`. */
|
|
12
|
+
max?: number;
|
|
13
|
+
/** Size applied to all avatars and the overflow chip. Defaults to `"md"`. */
|
|
14
|
+
size?: AvatarSize;
|
|
15
|
+
}
|
|
16
|
+
export declare const AvatarGroup: ({ avatars, max, size, className, "aria-label": ariaLabel, ...props }: AvatarGroupProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Avatar as e } from "../Avatar/Avatar.js";
|
|
2
|
+
import t from "./AvatarGroup.module.css.js";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/AvatarGroup/AvatarGroup.tsx
|
|
5
|
+
var i = ({ avatars: i, max: a = 5, size: o = "md", className: s, "aria-label": c, ...l }) => {
|
|
6
|
+
let u = i.length > a ? i.slice(0, a) : i, d = i.length > a ? i.length - a : 0, f = i.map((e) => e.name).filter(Boolean).join(", ");
|
|
7
|
+
return /* @__PURE__ */ r("span", {
|
|
8
|
+
role: "group",
|
|
9
|
+
"aria-label": c ?? (f ? d > 0 ? `${f} and ${d} more` : f : "Avatar group"),
|
|
10
|
+
className: [
|
|
11
|
+
t.group,
|
|
12
|
+
t[o],
|
|
13
|
+
s
|
|
14
|
+
].filter(Boolean).join(" "),
|
|
15
|
+
...l,
|
|
16
|
+
children: [u.map((r, i) => /* @__PURE__ */ n(e, {
|
|
17
|
+
name: r.name,
|
|
18
|
+
src: r.src,
|
|
19
|
+
alt: r.alt ?? r.name,
|
|
20
|
+
color: r.color,
|
|
21
|
+
size: o,
|
|
22
|
+
className: t.item
|
|
23
|
+
}, `${r.name ?? ""}-${r.src ?? ""}-${i}`)), d > 0 && /* @__PURE__ */ n("span", {
|
|
24
|
+
"aria-label": `+${d} more`,
|
|
25
|
+
className: [t.overflow, t[o]].filter(Boolean).join(" "),
|
|
26
|
+
children: /* @__PURE__ */ r("span", {
|
|
27
|
+
"aria-hidden": "true",
|
|
28
|
+
children: ["+", d]
|
|
29
|
+
})
|
|
30
|
+
})]
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { i as AvatarGroup };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=AvatarGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarGroup.js","names":[],"sources":["../../../src/components/AvatarGroup/AvatarGroup.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\n\nimport { Avatar, type AvatarColor, type AvatarSize } from '../Avatar';\n\nimport styles from './AvatarGroup.module.css';\n\nexport interface AvatarGroupItem {\n name?: string;\n src?: string;\n alt?: string;\n color?: AvatarColor;\n}\n\nexport interface AvatarGroupProps extends HTMLAttributes<HTMLSpanElement> {\n avatars: AvatarGroupItem[];\n /** Max visible avatars before showing overflow chip. Defaults to `5`. */\n max?: number;\n /** Size applied to all avatars and the overflow chip. Defaults to `\"md\"`. */\n size?: AvatarSize;\n}\n\nexport const AvatarGroup = ({\n avatars,\n max = 5,\n size = 'md',\n className,\n 'aria-label': ariaLabel,\n ...props\n}: AvatarGroupProps) => {\n const visible = avatars.length > max ? avatars.slice(0, max) : avatars;\n const overflowCount = avatars.length > max ? avatars.length - max : 0;\n\n const allNames = avatars\n .map((a) => a.name)\n .filter(Boolean)\n .join(', ');\n\n const label =\n ariaLabel ??\n (allNames\n ? overflowCount > 0\n ? `${allNames} and ${overflowCount} more`\n : allNames\n : 'Avatar group');\n\n const classes = [styles.group, styles[size], className].filter(Boolean).join(' ');\n\n return (\n <span role=\"group\" aria-label={label} className={classes} {...props}>\n {visible.map((item, index) => (\n <Avatar\n key={`${item.name ?? ''}-${item.src ?? ''}-${index}`}\n name={item.name}\n src={item.src}\n alt={item.alt ?? item.name}\n color={item.color}\n size={size}\n className={styles.item}\n />\n ))}\n {overflowCount > 0 && (\n <span\n aria-label={`+${overflowCount} more`}\n className={[styles.overflow, styles[size]].filter(Boolean).join(' ')}\n >\n <span aria-hidden=\"true\">+{overflowCount}</span>\n </span>\n )}\n </span>\n );\n};\n"],"mappings":";;;;AAqBA,IAAa,KAAe,EAC1B,YACA,SAAM,GACN,UAAO,MACP,cACA,cAAc,GACd,GAAG,QACmB;CACtB,IAAM,IAAU,EAAQ,SAAS,IAAM,EAAQ,MAAM,GAAG,CAAG,IAAI,GACzD,IAAgB,EAAQ,SAAS,IAAM,EAAQ,SAAS,IAAM,GAE9D,IAAW,EACd,KAAK,MAAM,EAAE,IAAI,EACjB,OAAO,OAAO,EACd,KAAK,IAAI;CAYZ,OACE,kBAAC,QAAD;EAAM,MAAK;EAAQ,cAVnB,MACC,IACG,IAAgB,IACd,GAAG,EAAS,OAAO,EAAc,SACjC,IACF;EAKkC,WAHxB;GAAC,EAAO;GAAO,EAAO;GAAO;EAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAG1B;EAAS,GAAI;YAA9D,CACG,EAAQ,KAAK,GAAM,MAClB,kBAAC,GAAD;GAEE,MAAM,EAAK;GACX,KAAK,EAAK;GACV,KAAK,EAAK,OAAO,EAAK;GACtB,OAAO,EAAK;GACN;GACN,WAAW,EAAO;EACnB,GAPM,GAAG,EAAK,QAAQ,GAAG,GAAG,EAAK,OAAO,GAAG,GAAG,GAO9C,CACF,GACA,IAAgB,KACf,kBAAC,QAAD;GACE,cAAY,IAAI,EAAc;GAC9B,WAAW,CAAC,EAAO,UAAU,EAAO,EAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;aAEnE,kBAAC,QAAD;IAAM,eAAY;cAAlB,CAAyB,KAAE,CAAoB;;EAC3C,CAAA,CAEJ;;AAEV"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarGroup.module.css.cjs","names":[],"sources":["../../../src/components/AvatarGroup/AvatarGroup.module.css"],"sourcesContent":["/* ─── Group ─────────────────────────────────────────────────────────────────── */\n\n.group {\n display: inline-flex;\n align-items: center;\n}\n\n/* ─── Item (each Avatar wrapper) ───────────────────────────────────────────── */\n\n.item {\n /* Separate-ring so overlapping avatars stay visually distinct */\n box-shadow:\n inset 0 0 0 1px rgba(0, 0, 0, 0.08),\n 0 0 0 2px #ffffff;\n flex-shrink: 0;\n}\n\n.item:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n/* ─── Size-specific overlap offsets ────────────────────────────────────────── */\n\n.sm .item:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.md .item:not(:first-child) {\n margin-inline-start: -8px;\n}\n\n.lg .item:not(:first-child) {\n margin-inline-start: -12px;\n}\n\n.xl .item:not(:first-child) {\n margin-inline-start: -16px;\n}\n\n/* ─── Overflow chip ─────────────────────────────────────────────────────────── */\n\n.overflow {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--gnome-radius-pill);\n overflow: hidden;\n flex-shrink: 0;\n user-select: none;\n background-color: var(--gnome-dark-2, #5e5c64);\n box-shadow:\n inset 0 0 0 1px rgba(0, 0, 0, 0.08),\n 0 0 0 2px #ffffff;\n font-family: var(--gnome-font-family);\n font-weight: var(--gnome-font-weight-semibold);\n color: #ffffff;\n line-height: 1;\n}\n\n.overflow:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.sm.overflow:not(:first-child),\n.sm .overflow:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.md.overflow:not(:first-child),\n.md .overflow:not(:first-child) {\n margin-inline-start: -8px;\n}\n\n.lg.overflow:not(:first-child),\n.lg .overflow:not(:first-child) {\n margin-inline-start: -12px;\n}\n\n.xl.overflow:not(:first-child),\n.xl .overflow:not(:first-child) {\n margin-inline-start: -16px;\n}\n\n/* ─── Overflow sizes ────────────────────────────────────────────────────────── */\n\n.sm.overflow {\n width: 24px;\n height: 24px;\n font-size: 0.5rem;\n}\n\n.md.overflow {\n width: 32px;\n height: 32px;\n font-size: 0.6rem;\n}\n\n.lg.overflow {\n width: 48px;\n height: 48px;\n font-size: 0.875rem;\n}\n\n.xl.overflow {\n width: 64px;\n height: 64px;\n font-size: 1.1rem;\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .item {\n box-shadow:\n inset 0 0 0 1px rgba(255, 255, 255, 0.08),\n 0 0 0 2px #242424;\n }\n\n .overflow {\n box-shadow:\n inset 0 0 0 1px rgba(255, 255, 255, 0.08),\n 0 0 0 2px #242424;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var e = {
|
|
2
|
+
group: "_group_18nkh_3",
|
|
3
|
+
item: "_item_18nkh_10",
|
|
4
|
+
sm: "_sm_18nkh_24",
|
|
5
|
+
md: "_md_18nkh_28",
|
|
6
|
+
lg: "_lg_18nkh_32",
|
|
7
|
+
xl: "_xl_18nkh_36",
|
|
8
|
+
overflow: "_overflow_18nkh_42"
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { e as default };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=AvatarGroup.module.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarGroup.module.css.js","names":[],"sources":["../../../src/components/AvatarGroup/AvatarGroup.module.css"],"sourcesContent":["/* ─── Group ─────────────────────────────────────────────────────────────────── */\n\n.group {\n display: inline-flex;\n align-items: center;\n}\n\n/* ─── Item (each Avatar wrapper) ───────────────────────────────────────────── */\n\n.item {\n /* Separate-ring so overlapping avatars stay visually distinct */\n box-shadow:\n inset 0 0 0 1px rgba(0, 0, 0, 0.08),\n 0 0 0 2px #ffffff;\n flex-shrink: 0;\n}\n\n.item:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n/* ─── Size-specific overlap offsets ────────────────────────────────────────── */\n\n.sm .item:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.md .item:not(:first-child) {\n margin-inline-start: -8px;\n}\n\n.lg .item:not(:first-child) {\n margin-inline-start: -12px;\n}\n\n.xl .item:not(:first-child) {\n margin-inline-start: -16px;\n}\n\n/* ─── Overflow chip ─────────────────────────────────────────────────────────── */\n\n.overflow {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--gnome-radius-pill);\n overflow: hidden;\n flex-shrink: 0;\n user-select: none;\n background-color: var(--gnome-dark-2, #5e5c64);\n box-shadow:\n inset 0 0 0 1px rgba(0, 0, 0, 0.08),\n 0 0 0 2px #ffffff;\n font-family: var(--gnome-font-family);\n font-weight: var(--gnome-font-weight-semibold);\n color: #ffffff;\n line-height: 1;\n}\n\n.overflow:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.sm.overflow:not(:first-child),\n.sm .overflow:not(:first-child) {\n margin-inline-start: -6px;\n}\n\n.md.overflow:not(:first-child),\n.md .overflow:not(:first-child) {\n margin-inline-start: -8px;\n}\n\n.lg.overflow:not(:first-child),\n.lg .overflow:not(:first-child) {\n margin-inline-start: -12px;\n}\n\n.xl.overflow:not(:first-child),\n.xl .overflow:not(:first-child) {\n margin-inline-start: -16px;\n}\n\n/* ─── Overflow sizes ────────────────────────────────────────────────────────── */\n\n.sm.overflow {\n width: 24px;\n height: 24px;\n font-size: 0.5rem;\n}\n\n.md.overflow {\n width: 32px;\n height: 32px;\n font-size: 0.6rem;\n}\n\n.lg.overflow {\n width: 48px;\n height: 48px;\n font-size: 0.875rem;\n}\n\n.xl.overflow {\n width: 64px;\n height: 64px;\n font-size: 1.1rem;\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .item {\n box-shadow:\n inset 0 0 0 1px rgba(255, 255, 255, 0.08),\n 0 0 0 2px #242424;\n }\n\n .overflow {\n box-shadow:\n inset 0 0 0 1px rgba(255, 255, 255, 0.08),\n 0 0 0 2px #242424;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./AvatarGroup/AvatarGroup.cjs");exports.AvatarGroup=e.AvatarGroup;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../Dialog/dialogUtils.cjs"),t=require("./BottomSheet.module.css.cjs");let n=require("react"),r=require("react-dom"),i=require("react/jsx-runtime");var a=`button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`,o=({open:
|
|
1
|
+
const e=require("../Dialog/dialogUtils.cjs"),t=require("./BottomSheet.module.css.cjs");let n=require("react"),r=require("react-dom"),i=require("react/jsx-runtime");var a=`button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`,o=150,s=200,c=({open:c,title:l,children:u,onClose:d,closeOnBackdrop:f=!0,className:p,...m})=>{let h=(0,n.useRef)(null),g=(0,n.useRef)(null),_=(0,n.useId)(),v=(0,n.useRef)(null),[y,b]=(0,n.useState)(c),[x,S]=(0,n.useState)(c),[C,w]=(0,n.useState)(!1),T=(0,n.useRef)(c),E=(0,n.useRef)(!1),D=(0,n.useRef)(!1),O=(0,n.useRef)(0),k=(0,n.useRef)(0);e.useBodyScrollLock(c),(0,n.useEffect)(()=>{let e=T.current;T.current=c,c?(b(!0),S(!0),w(!1)):e&&!E.current?(S(!1),typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches?b(!1):w(!0)):e&&E.current&&(E.current=!1,S(!1),b(!1))},[c]),(0,n.useEffect)(()=>{c?(v.current=document.activeElement,(h.current?.querySelector(a))?.focus()):v.current?.focus()},[c]);let A=(0,n.useCallback)(e=>{if(e.key===`Escape`){e.preventDefault(),d?.();return}if(e.key!==`Tab`)return;let t=Array.from(h.current?.querySelectorAll(a)??[]);if(t.length===0)return;let n=t[0],r=t[t.length-1];e.shiftKey?document.activeElement===n&&(e.preventDefault(),r.focus()):document.activeElement===r&&(e.preventDefault(),n.focus())},[d]);(0,n.useEffect)(()=>{if(!C)return;let e=window.setTimeout(()=>{b(!1),w(!1)},s);return()=>window.clearTimeout(e)},[C]);let j=(0,n.useCallback)(e=>{D.current=!0,O.current=e.clientY,k.current=0,e.currentTarget.setPointerCapture(e.pointerId),h.current&&(h.current.style.animation=`none`,h.current.classList.add(t.default.dragging)),S(!1)},[]),M=(0,n.useCallback)(e=>{if(!D.current)return;let t=Math.max(0,e.clientY-O.current);k.current=t,h.current&&(h.current.style.transform=`translateY(${t}px)`)},[]),N=(0,n.useCallback)(()=>{if(!D.current)return;D.current=!1;let e=k.current;if(k.current=0,h.current?.classList.remove(t.default.dragging),e>=o){E.current=!0;let e=typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches,t=h.current,n=g.current;!e&&t&&n?(t.style.transition=`transform ${s}ms ease`,t.style.transform=`translateY(100%)`,n.style.transition=`opacity ${s}ms ease`,n.style.opacity=`0`,setTimeout(()=>{t.style.transition=``,t.style.transform=``,n.style.transition=``,n.style.opacity=``,d?.()},s)):d?.()}else h.current&&(h.current.style.animation=``,h.current.style.transform=``)},[d]);if(!y)return null;let P=(0,i.jsx)(`div`,{ref:g,className:[t.default.backdrop,C?t.default.closing:null].filter(Boolean).join(` `),onClick:f?d:void 0,children:(0,i.jsxs)(`div`,{ref:h,role:`dialog`,"aria-modal":`true`,"aria-labelledby":l?_:void 0,className:[t.default.sheet,x?t.default.entering:null,C?t.default.closing:null,p].filter(Boolean).join(` `),onAnimationEnd:e=>{e.target===e.currentTarget&&x&&S(!1)},onKeyDown:A,onClick:e=>e.stopPropagation(),...m,children:[(0,i.jsx)(`div`,{className:t.default.handle,"aria-hidden":`true`,onPointerDown:j,onPointerMove:M,onPointerUp:N,onPointerCancel:N,children:(0,i.jsx)(`div`,{className:t.default.handleBar})}),l&&(0,i.jsx)(`div`,{id:_,className:t.default.title,children:l}),u&&(0,i.jsx)(`div`,{className:t.default.content,children:u})]})});return typeof document>`u`?P:(0,r.createPortal)(P,document.body)};exports.BottomSheet=c;
|
|
2
2
|
//# sourceMappingURL=BottomSheet.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n useBodyScrollLock(open);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div className={styles.backdrop} onClick={closeOnBackdrop ? onClose : undefined}>\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"oKAgBA,IAAM,EACJ,2IA4BW,GAAe,CAC1B,OACA,QACA,WACA,UACA,kBAAkB,GAClB,YACA,GAAG,KACmB,CACtB,IAAM,GAAA,EAAA,EAAA,QAAkC,IAAI,EACtC,GAAA,EAAA,EAAA,OAAgB,EAChB,GAAA,EAAA,EAAA,QAA2C,IAAI,EAErD,EAAA,kBAAkB,CAAI,GAGtB,EAAA,EAAA,eAAgB,CACV,GACF,EAAkB,QAAU,SAAS,eAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,GAEV,EAAmB,SAAgC,MAAM,CAE7D,EAAG,CAAC,CAAI,CAAC,EAGT,IAAM,GAAA,EAAA,EAAA,aACH,GAAqC,CACpC,GAAI,EAAE,MAAQ,SAAU,CACtB,EAAE,eAAe,EACjB,IAAU,EAEV,MACF,CAEA,GAAI,EAAE,MAAQ,MACZ,OAGF,IAAM,EAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,GAAK,CAAC,CACjE,EAEA,GAAI,EAAU,SAAW,EACvB,OAGF,IAAM,EAAQ,EAAU,GAClB,EAAO,EAAU,EAAU,OAAS,GAEtC,EAAE,SACA,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAK,MAAM,GAGT,SAAS,gBAAkB,IAC7B,EAAE,eAAe,EACjB,EAAM,MAAM,EAGlB,EACA,CAAC,CAAO,CACV,EAEA,GAAI,CAAC,EACH,OAAO,KAGT,IAAM,GACJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAU,QAAS,EAAkB,EAAU,IAAA,aACpE,EAAA,EAAA,MAAC,MAAD,CACE,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAQ,EAAU,IAAA,GACnC,UAAW,CAAC,EAAA,QAAO,MAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAC7D,UAAW,EACX,QAAU,GAAM,EAAE,gBAAgB,EAClC,GAAI,WARN,EAWE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAQ,cAAY,iBACzC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SAAY,CAAA,CAChC,CAAA,EAGJ,IACC,EAAA,EAAA,KAAC,MAAD,CAAK,GAAI,EAAS,UAAW,EAAA,QAAO,eACjC,CACE,CAAA,EAIN,IAAY,EAAA,EAAA,KAAC,MAAD,CAAK,UAAW,EAAA,QAAO,QAAU,UAAc,CAAA,CACzD,GACF,CAAA,EAOP,OAJI,OAAO,SAAa,IACf,GAGT,EAAA,EAAA,cAAoB,EAAM,SAAS,IAAI,CACzC"}
|
|
1
|
+
{"version":3,"file":"BottomSheet.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst DRAG_CLOSE_THRESHOLD = 150;\nconst CLOSE_ANIM_DURATION = 200;\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape, backdrop click, or drag down). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape, backdrop click, or by\n * dragging the handle bar downward past 150 px. Plays slide-out animation on close.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n // Animation state\n const [isVisible, setIsVisible] = useState(open);\n const [isEntering, setIsEntering] = useState(open);\n const [isClosing, setIsClosing] = useState(false);\n const prevOpen = useRef(open);\n const dragClosing = useRef(false);\n\n // Drag state (refs avoid re-renders during drag)\n const isDragging = useRef(false);\n const dragStartY = useRef(0);\n const sheetDragY = useRef(0);\n\n useBodyScrollLock(open);\n\n // Track open → closed transitions\n useEffect(() => {\n const wasOpen = prevOpen.current;\n prevOpen.current = open;\n\n if (open) {\n setIsVisible(true);\n setIsEntering(true);\n setIsClosing(false);\n } else if (wasOpen && !dragClosing.current) {\n setIsEntering(false);\n\n const reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n if (reducedMotion) {\n setIsVisible(false);\n } else {\n setIsClosing(true);\n }\n } else if (wasOpen && dragClosing.current) {\n dragClosing.current = false;\n setIsEntering(false);\n setIsVisible(false);\n }\n }, [open]);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n // Unmount after exit animation duration elapses\n useEffect(() => {\n if (!isClosing) {\n return;\n }\n\n const id = window.setTimeout(() => {\n setIsVisible(false);\n setIsClosing(false);\n }, CLOSE_ANIM_DURATION);\n\n return () => window.clearTimeout(id);\n }, [isClosing]);\n\n // ─── Drag-to-dismiss ─────────────────────────────────────────────────────────\n\n const handlePointerDown = useCallback((e: PointerEvent<HTMLDivElement>) => {\n isDragging.current = true;\n dragStartY.current = e.clientY;\n sheetDragY.current = 0;\n e.currentTarget.setPointerCapture(e.pointerId);\n\n if (sheetRef.current) {\n // Cancel any active entry animation immediately so inline style.transform\n // takes effect. CSS animations sit above the author cascade layer and would\n // otherwise override the inline transform set during drag.\n sheetRef.current.style.animation = 'none';\n sheetRef.current.classList.add(styles.dragging);\n }\n\n setIsEntering(false);\n }, []);\n\n const handlePointerMove = useCallback((e: PointerEvent<HTMLDivElement>) => {\n if (!isDragging.current) {\n return;\n }\n\n const delta = Math.max(0, e.clientY - dragStartY.current);\n\n sheetDragY.current = delta;\n\n if (sheetRef.current) {\n sheetRef.current.style.transform = `translateY(${delta}px)`;\n }\n }, []);\n\n const handlePointerUp = useCallback(() => {\n if (!isDragging.current) {\n return;\n }\n isDragging.current = false;\n\n const delta = sheetDragY.current;\n\n sheetDragY.current = 0;\n sheetRef.current?.classList.remove(styles.dragging);\n\n if (delta >= DRAG_CLOSE_THRESHOLD) {\n dragClosing.current = true;\n\n const reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n const sheet = sheetRef.current;\n const backdrop = backdropRef.current;\n\n if (!reducedMotion && sheet && backdrop) {\n sheet.style.transition = `transform ${CLOSE_ANIM_DURATION}ms ease`;\n sheet.style.transform = 'translateY(100%)';\n backdrop.style.transition = `opacity ${CLOSE_ANIM_DURATION}ms ease`;\n backdrop.style.opacity = '0';\n\n setTimeout(() => {\n sheet.style.transition = '';\n sheet.style.transform = '';\n backdrop.style.transition = '';\n backdrop.style.opacity = '';\n onClose?.();\n }, CLOSE_ANIM_DURATION);\n } else {\n onClose?.();\n }\n } else if (sheetRef.current) {\n // Snap back — restore animation override and clear transform so CSS transition animates to 0\n sheetRef.current.style.animation = '';\n sheetRef.current.style.transform = '';\n }\n }, [onClose]);\n\n if (!isVisible) {\n return null;\n }\n\n const node = (\n <div\n ref={backdropRef}\n className={[styles.backdrop, isClosing ? styles.closing : null].filter(Boolean).join(' ')}\n onClick={closeOnBackdrop ? onClose : undefined}\n >\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[\n styles.sheet,\n isEntering ? styles.entering : null,\n isClosing ? styles.closing : null,\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n onAnimationEnd={(e) => {\n if (e.target === e.currentTarget && isEntering) {\n setIsEntering(false);\n }\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar — drag downward to dismiss */}\n <div\n className={styles.handle}\n aria-hidden=\"true\"\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n >\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ export interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, '
|
|
|
7
7
|
*/
|
|
8
8
|
title?: ReactNode;
|
|
9
9
|
children?: ReactNode;
|
|
10
|
-
/** Called when the user dismisses the sheet (Escape or
|
|
10
|
+
/** Called when the user dismisses the sheet (Escape, backdrop click, or drag down). */
|
|
11
11
|
onClose?: () => void;
|
|
12
12
|
/**
|
|
13
13
|
* Whether clicking the backdrop closes the sheet.
|
|
@@ -19,8 +19,8 @@ export interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, '
|
|
|
19
19
|
* Slide-up panel that overlays content from the bottom edge.
|
|
20
20
|
*
|
|
21
21
|
* Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on
|
|
22
|
-
* `document.body`. Traps focus, closes on Escape
|
|
23
|
-
*
|
|
22
|
+
* `document.body`. Traps focus, closes on Escape, backdrop click, or by
|
|
23
|
+
* dragging the handle bar downward past 150 px. Plays slide-out animation on close.
|
|
24
24
|
*
|
|
25
25
|
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html
|
|
26
26
|
*/
|
|
@@ -1,59 +1,100 @@
|
|
|
1
1
|
import { useBodyScrollLock as e } from "../Dialog/dialogUtils.js";
|
|
2
2
|
import t from "./BottomSheet.module.css.js";
|
|
3
|
-
import { useCallback as n, useEffect as r, useId as i, useRef as a } from "react";
|
|
4
|
-
import { createPortal as
|
|
5
|
-
import { jsx as
|
|
3
|
+
import { useCallback as n, useEffect as r, useId as i, useRef as a, useState as o } from "react";
|
|
4
|
+
import { createPortal as s } from "react-dom";
|
|
5
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/BottomSheet/BottomSheet.tsx
|
|
7
|
-
var
|
|
8
|
-
let
|
|
9
|
-
e(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
var u = "button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])", d = 150, f = 200, p = ({ open: p, title: m, children: h, onClose: g, closeOnBackdrop: _ = !0, className: v, ...y }) => {
|
|
8
|
+
let b = a(null), x = a(null), S = i(), C = a(null), [w, T] = o(p), [E, D] = o(p), [O, k] = o(!1), A = a(p), j = a(!1), M = a(!1), N = a(0), P = a(0);
|
|
9
|
+
e(p), r(() => {
|
|
10
|
+
let e = A.current;
|
|
11
|
+
A.current = p, p ? (T(!0), D(!0), k(!1)) : e && !j.current ? (D(!1), typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches ? T(!1) : k(!0)) : e && j.current && (j.current = !1, D(!1), T(!1));
|
|
12
|
+
}, [p]), r(() => {
|
|
13
|
+
p ? (C.current = document.activeElement, (b.current?.querySelector(u))?.focus()) : C.current?.focus();
|
|
14
|
+
}, [p]);
|
|
15
|
+
let F = n((e) => {
|
|
13
16
|
if (e.key === "Escape") {
|
|
14
|
-
e.preventDefault(),
|
|
17
|
+
e.preventDefault(), g?.();
|
|
15
18
|
return;
|
|
16
19
|
}
|
|
17
20
|
if (e.key !== "Tab") return;
|
|
18
|
-
let t = Array.from(
|
|
21
|
+
let t = Array.from(b.current?.querySelectorAll(u) ?? []);
|
|
19
22
|
if (t.length === 0) return;
|
|
20
23
|
let n = t[0], r = t[t.length - 1];
|
|
21
24
|
e.shiftKey ? document.activeElement === n && (e.preventDefault(), r.focus()) : document.activeElement === r && (e.preventDefault(), n.focus());
|
|
22
|
-
}, [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
}, [g]);
|
|
26
|
+
r(() => {
|
|
27
|
+
if (!O) return;
|
|
28
|
+
let e = window.setTimeout(() => {
|
|
29
|
+
T(!1), k(!1);
|
|
30
|
+
}, f);
|
|
31
|
+
return () => window.clearTimeout(e);
|
|
32
|
+
}, [O]);
|
|
33
|
+
let I = n((e) => {
|
|
34
|
+
M.current = !0, N.current = e.clientY, P.current = 0, e.currentTarget.setPointerCapture(e.pointerId), b.current && (b.current.style.animation = "none", b.current.classList.add(t.dragging)), D(!1);
|
|
35
|
+
}, []), L = n((e) => {
|
|
36
|
+
if (!M.current) return;
|
|
37
|
+
let t = Math.max(0, e.clientY - N.current);
|
|
38
|
+
P.current = t, b.current && (b.current.style.transform = `translateY(${t}px)`);
|
|
39
|
+
}, []), R = n(() => {
|
|
40
|
+
if (!M.current) return;
|
|
41
|
+
M.current = !1;
|
|
42
|
+
let e = P.current;
|
|
43
|
+
if (P.current = 0, b.current?.classList.remove(t.dragging), e >= d) {
|
|
44
|
+
j.current = !0;
|
|
45
|
+
let e = typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches, t = b.current, n = x.current;
|
|
46
|
+
!e && t && n ? (t.style.transition = `transform ${f}ms ease`, t.style.transform = "translateY(100%)", n.style.transition = `opacity ${f}ms ease`, n.style.opacity = "0", setTimeout(() => {
|
|
47
|
+
t.style.transition = "", t.style.transform = "", n.style.transition = "", n.style.opacity = "", g?.();
|
|
48
|
+
}, f)) : g?.();
|
|
49
|
+
} else b.current && (b.current.style.animation = "", b.current.style.transform = "");
|
|
50
|
+
}, [g]);
|
|
51
|
+
if (!w) return null;
|
|
52
|
+
let z = /* @__PURE__ */ c("div", {
|
|
53
|
+
ref: x,
|
|
54
|
+
className: [t.backdrop, O ? t.closing : null].filter(Boolean).join(" "),
|
|
55
|
+
onClick: _ ? g : void 0,
|
|
56
|
+
children: /* @__PURE__ */ l("div", {
|
|
57
|
+
ref: b,
|
|
29
58
|
role: "dialog",
|
|
30
59
|
"aria-modal": "true",
|
|
31
|
-
"aria-labelledby":
|
|
32
|
-
className: [
|
|
33
|
-
|
|
60
|
+
"aria-labelledby": m ? S : void 0,
|
|
61
|
+
className: [
|
|
62
|
+
t.sheet,
|
|
63
|
+
E ? t.entering : null,
|
|
64
|
+
O ? t.closing : null,
|
|
65
|
+
v
|
|
66
|
+
].filter(Boolean).join(" "),
|
|
67
|
+
onAnimationEnd: (e) => {
|
|
68
|
+
e.target === e.currentTarget && E && D(!1);
|
|
69
|
+
},
|
|
70
|
+
onKeyDown: F,
|
|
34
71
|
onClick: (e) => e.stopPropagation(),
|
|
35
|
-
...
|
|
72
|
+
...y,
|
|
36
73
|
children: [
|
|
37
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ c("div", {
|
|
38
75
|
className: t.handle,
|
|
39
76
|
"aria-hidden": "true",
|
|
40
|
-
|
|
77
|
+
onPointerDown: I,
|
|
78
|
+
onPointerMove: L,
|
|
79
|
+
onPointerUp: R,
|
|
80
|
+
onPointerCancel: R,
|
|
81
|
+
children: /* @__PURE__ */ c("div", { className: t.handleBar })
|
|
41
82
|
}),
|
|
42
|
-
|
|
43
|
-
id:
|
|
83
|
+
m && /* @__PURE__ */ c("div", {
|
|
84
|
+
id: S,
|
|
44
85
|
className: t.title,
|
|
45
|
-
children:
|
|
86
|
+
children: m
|
|
46
87
|
}),
|
|
47
|
-
|
|
88
|
+
h && /* @__PURE__ */ c("div", {
|
|
48
89
|
className: t.content,
|
|
49
|
-
children:
|
|
90
|
+
children: h
|
|
50
91
|
})
|
|
51
92
|
]
|
|
52
93
|
})
|
|
53
94
|
});
|
|
54
|
-
return typeof document > "u" ?
|
|
95
|
+
return typeof document > "u" ? z : s(z, document.body);
|
|
55
96
|
};
|
|
56
97
|
//#endregion
|
|
57
|
-
export {
|
|
98
|
+
export { p as BottomSheet };
|
|
58
99
|
|
|
59
100
|
//# sourceMappingURL=BottomSheet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape or backdrop click). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape or backdrop click.\n * The handle bar is decorative — drag-to-close is not implemented.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n useBodyScrollLock(open);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n if (!open) {\n return null;\n }\n\n const node = (\n <div className={styles.backdrop} onClick={closeOnBackdrop ? onClose : undefined}>\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[styles.sheet, className].filter(Boolean).join(' ')}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar */}\n <div className={styles.handle} aria-hidden=\"true\">\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":";;;;;;AAgBA,IAAM,IACJ,8IA4BW,KAAe,EAC1B,SACA,UACA,aACA,YACA,qBAAkB,IAClB,cACA,GAAG,QACmB;CACtB,IAAM,IAAW,EAAuB,IAAI,GACtC,IAAU,EAAM,GAChB,IAAoB,EAAuB,IAAI;CAKrD,AAHA,EAAkB,CAAI,GAGtB,QAAgB;EACd,AAAI,KACF,EAAkB,UAAU,SAAS,gBAC1B,EAAS,SAAS,cAA2B,CAAS,IAE7D,MAAM,KAEV,EAAmB,SAAgC,MAAM;CAE7D,GAAG,CAAC,CAAI,CAAC;CAGT,IAAM,IAAgB,GACnB,MAAqC;EACpC,IAAI,EAAE,QAAQ,UAAU;GAEtB,AADA,EAAE,eAAe,GACjB,IAAU;GAEV;EACF;EAEA,IAAI,EAAE,QAAQ,OACZ;EAGF,IAAM,IAAY,MAAM,KACtB,EAAS,SAAS,iBAA8B,CAAS,KAAK,CAAC,CACjE;EAEA,IAAI,EAAU,WAAW,GACvB;EAGF,IAAM,IAAQ,EAAU,IAClB,IAAO,EAAU,EAAU,SAAS;EAE1C,AAAI,EAAE,WACA,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAK,MAAM,KAGT,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACjB,EAAM,MAAM;CAGlB,GACA,CAAC,CAAO,CACV;CAEA,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IACJ,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAU,SAAS,IAAkB,IAAU,KAAA;YACpE,kBAAC,OAAD;GACE,KAAK;GACL,MAAK;GACL,cAAW;GACX,mBAAiB,IAAQ,IAAU,KAAA;GACnC,WAAW,CAAC,EAAO,OAAO,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;GAC7D,WAAW;GACX,UAAU,MAAM,EAAE,gBAAgB;GAClC,GAAI;aARN;IAWE,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAQ,eAAY;eACzC,kBAAC,OAAD,EAAK,WAAW,EAAO,UAAY,CAAA;IAChC,CAAA;IAGJ,KACC,kBAAC,OAAD;KAAK,IAAI;KAAS,WAAW,EAAO;eACjC;IACE,CAAA;IAIN,KAAY,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAU;IAAc,CAAA;GACzD;;CACF,CAAA;CAOP,OAJI,OAAO,WAAa,MACf,IAGF,EAAa,GAAM,SAAS,IAAI;AACzC"}
|
|
1
|
+
{"version":3,"file":"BottomSheet.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.tsx"],"sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\n\nimport { createPortal } from 'react-dom';\n\nimport { useBodyScrollLock } from '../Dialog/dialogUtils';\n\nimport styles from './BottomSheet.module.css';\n\nconst FOCUSABLE =\n 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst DRAG_CLOSE_THRESHOLD = 150;\nconst CLOSE_ANIM_DURATION = 200;\n\nexport interface BottomSheetProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Whether the sheet is visible. */\n open: boolean;\n /**\n * Optional heading shown in the drag handle area.\n */\n title?: ReactNode;\n children?: ReactNode;\n /** Called when the user dismisses the sheet (Escape, backdrop click, or drag down). */\n onClose?: () => void;\n /**\n * Whether clicking the backdrop closes the sheet.\n * Defaults to `true`.\n */\n closeOnBackdrop?: boolean;\n}\n\n/**\n * Slide-up panel that overlays content from the bottom edge.\n *\n * Mirrors `AdwBottomSheet` (libadwaita 1.6+). Renders into a portal on\n * `document.body`. Traps focus, closes on Escape, backdrop click, or by\n * dragging the handle bar downward past 150 px. Plays slide-out animation on close.\n *\n * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html\n */\nexport const BottomSheet = ({\n open,\n title,\n children,\n onClose,\n closeOnBackdrop = true,\n className,\n ...props\n}: BottomSheetProps) => {\n const sheetRef = useRef<HTMLDivElement>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const previouslyFocused = useRef<Element | null>(null);\n\n // Animation state\n const [isVisible, setIsVisible] = useState(open);\n const [isEntering, setIsEntering] = useState(open);\n const [isClosing, setIsClosing] = useState(false);\n const prevOpen = useRef(open);\n const dragClosing = useRef(false);\n\n // Drag state (refs avoid re-renders during drag)\n const isDragging = useRef(false);\n const dragStartY = useRef(0);\n const sheetDragY = useRef(0);\n\n useBodyScrollLock(open);\n\n // Track open → closed transitions\n useEffect(() => {\n const wasOpen = prevOpen.current;\n prevOpen.current = open;\n\n if (open) {\n setIsVisible(true);\n setIsEntering(true);\n setIsClosing(false);\n } else if (wasOpen && !dragClosing.current) {\n setIsEntering(false);\n\n const reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n if (reducedMotion) {\n setIsVisible(false);\n } else {\n setIsClosing(true);\n }\n } else if (wasOpen && dragClosing.current) {\n dragClosing.current = false;\n setIsEntering(false);\n setIsVisible(false);\n }\n }, [open]);\n\n // Save / restore focus\n useEffect(() => {\n if (open) {\n previouslyFocused.current = document.activeElement;\n const el = sheetRef.current?.querySelector<HTMLElement>(FOCUSABLE);\n\n el?.focus();\n } else {\n (previouslyFocused.current as HTMLElement | null)?.focus();\n }\n }, [open]);\n\n // Focus trap + Escape\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const focusable = Array.from(\n sheetRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [],\n );\n\n if (focusable.length === 0) {\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n },\n [onClose],\n );\n\n // Unmount after exit animation duration elapses\n useEffect(() => {\n if (!isClosing) {\n return;\n }\n\n const id = window.setTimeout(() => {\n setIsVisible(false);\n setIsClosing(false);\n }, CLOSE_ANIM_DURATION);\n\n return () => window.clearTimeout(id);\n }, [isClosing]);\n\n // ─── Drag-to-dismiss ─────────────────────────────────────────────────────────\n\n const handlePointerDown = useCallback((e: PointerEvent<HTMLDivElement>) => {\n isDragging.current = true;\n dragStartY.current = e.clientY;\n sheetDragY.current = 0;\n e.currentTarget.setPointerCapture(e.pointerId);\n\n if (sheetRef.current) {\n // Cancel any active entry animation immediately so inline style.transform\n // takes effect. CSS animations sit above the author cascade layer and would\n // otherwise override the inline transform set during drag.\n sheetRef.current.style.animation = 'none';\n sheetRef.current.classList.add(styles.dragging);\n }\n\n setIsEntering(false);\n }, []);\n\n const handlePointerMove = useCallback((e: PointerEvent<HTMLDivElement>) => {\n if (!isDragging.current) {\n return;\n }\n\n const delta = Math.max(0, e.clientY - dragStartY.current);\n\n sheetDragY.current = delta;\n\n if (sheetRef.current) {\n sheetRef.current.style.transform = `translateY(${delta}px)`;\n }\n }, []);\n\n const handlePointerUp = useCallback(() => {\n if (!isDragging.current) {\n return;\n }\n isDragging.current = false;\n\n const delta = sheetDragY.current;\n\n sheetDragY.current = 0;\n sheetRef.current?.classList.remove(styles.dragging);\n\n if (delta >= DRAG_CLOSE_THRESHOLD) {\n dragClosing.current = true;\n\n const reducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n const sheet = sheetRef.current;\n const backdrop = backdropRef.current;\n\n if (!reducedMotion && sheet && backdrop) {\n sheet.style.transition = `transform ${CLOSE_ANIM_DURATION}ms ease`;\n sheet.style.transform = 'translateY(100%)';\n backdrop.style.transition = `opacity ${CLOSE_ANIM_DURATION}ms ease`;\n backdrop.style.opacity = '0';\n\n setTimeout(() => {\n sheet.style.transition = '';\n sheet.style.transform = '';\n backdrop.style.transition = '';\n backdrop.style.opacity = '';\n onClose?.();\n }, CLOSE_ANIM_DURATION);\n } else {\n onClose?.();\n }\n } else if (sheetRef.current) {\n // Snap back — restore animation override and clear transform so CSS transition animates to 0\n sheetRef.current.style.animation = '';\n sheetRef.current.style.transform = '';\n }\n }, [onClose]);\n\n if (!isVisible) {\n return null;\n }\n\n const node = (\n <div\n ref={backdropRef}\n className={[styles.backdrop, isClosing ? styles.closing : null].filter(Boolean).join(' ')}\n onClick={closeOnBackdrop ? onClose : undefined}\n >\n <div\n ref={sheetRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n className={[\n styles.sheet,\n isEntering ? styles.entering : null,\n isClosing ? styles.closing : null,\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n onAnimationEnd={(e) => {\n if (e.target === e.currentTarget && isEntering) {\n setIsEntering(false);\n }\n }}\n onKeyDown={handleKeyDown}\n onClick={(e) => e.stopPropagation()}\n {...props}\n >\n {/* Handle bar — drag downward to dismiss */}\n <div\n className={styles.handle}\n aria-hidden=\"true\"\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n >\n <div className={styles.handleBar} />\n </div>\n\n {/* Optional title */}\n {title && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n\n {/* Content */}\n {children && <div className={styles.content}>{children}</div>}\n </div>\n </div>\n );\n\n if (typeof document === 'undefined') {\n return node;\n }\n\n return createPortal(node, document.body);\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={backdrop:`
|
|
1
|
+
var e={backdrop:`_backdrop_mrs02_3`,"backdrop-in":`_backdrop-in_mrs02_1`,closing:`_closing_mrs02_19`,"backdrop-out":`_backdrop-out_mrs02_1`,sheet:`_sheet_mrs02_43`,entering:`_entering_mrs02_61`,"sheet-in":`_sheet-in_mrs02_1`,"sheet-out":`_sheet-out_mrs02_1`,dragging:`_dragging_mrs02_70`,handle:`_handle_mrs02_94`,handleBar:`_handleBar_mrs02_108`,title:`_title_mrs02_119`,content:`_content_mrs02_132`};exports.default=e;
|
|
2
2
|
//# sourceMappingURL=BottomSheet.module.css.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.module.css.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.module.css"],"sourcesContent":["/* ─── Backdrop ──────────────────────────────────────────────────────────────── */\n\n.backdrop {\n position: fixed;\n inset: 0;\n z-index: 10000;\n\n display: flex;\n align-items: flex-end;\n justify-content: center;\n\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n\n animation: backdrop-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes backdrop-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ─── Sheet ─────────────────────────────────────────────────────────────────── */\n\n.sheet {\n width: min(560px, 100vw);\n max-height: 90dvh;\n overflow-y: auto;\n\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #fafafa));\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n\n border-radius: var(--gnome-radius-xl, 16px) var(--gnome-radius-xl, 16px) 0 0;\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.18),\n 0 0 0 1px rgba(0, 0, 0, 0.06);\n\n animation: sheet-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes sheet-in {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n/* ─── Handle bar ────────────────────────────────────────────────────────────── */\n\n.handle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--gnome-space-2, 12px) 0 var(--gnome-space-1, 6px);\n}\n\n.handleBar {\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background-color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n opacity: 0.2;\n}\n\n/* ─── Title ─────────────────────────────────────────────────────────────────── */\n\n.title {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-2, 12px);\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-title-4, 1.125rem);\n font-weight: var(--gnome-font-weight-bold, 700);\n line-height: var(--gnome-line-height-title, 1.3);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n text-align: center;\n}\n\n/* ─── Content ───────────────────────────────────────────────────────────────── */\n\n.content {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-4, 24px);\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .backdrop {\n background-color: rgba(0, 0, 0, 0.65);\n }\n\n .sheet {\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #242424));\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.45),\n 0 0 0 1px rgba(255, 255, 255, 0.06);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .backdrop,\n .sheet {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"BottomSheet.module.css.cjs","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.module.css"],"sourcesContent":["/* ─── Backdrop ──────────────────────────────────────────────────────────────── */\n\n.backdrop {\n position: fixed;\n inset: 0;\n z-index: 10000;\n\n display: flex;\n align-items: flex-end;\n justify-content: center;\n\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n\n animation: backdrop-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n.backdrop.closing {\n animation: backdrop-out var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes backdrop-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes backdrop-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n/* ─── Sheet ─────────────────────────────────────────────────────────────────── */\n\n.sheet {\n width: min(560px, 100vw);\n max-height: 90dvh;\n overflow-y: auto;\n\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #fafafa));\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n\n border-radius: var(--gnome-radius-xl, 16px) var(--gnome-radius-xl, 16px) 0 0;\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.18),\n 0 0 0 1px rgba(0, 0, 0, 0.06);\n\n /* Snap-back transition after releasing a partial drag */\n transition: transform 200ms var(--gnome-easing-default, ease);\n will-change: transform;\n}\n\n.sheet.entering {\n animation: sheet-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n.sheet.closing {\n animation: sheet-out var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n/* Disable transition while actively dragging so the sheet follows the pointer instantly */\n.sheet.dragging {\n transition: none;\n}\n\n@keyframes sheet-in {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes sheet-out {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n\n/* ─── Handle bar ────────────────────────────────────────────────────────────── */\n\n.handle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--gnome-space-2, 12px) 0 var(--gnome-space-1, 6px);\n cursor: grab;\n /* Prevents the browser from hijacking the pointer for scroll while dragging */\n touch-action: none;\n}\n\n.handle:active {\n cursor: grabbing;\n}\n\n.handleBar {\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background-color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n opacity: 0.2;\n pointer-events: none;\n}\n\n/* ─── Title ─────────────────────────────────────────────────────────────────── */\n\n.title {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-2, 12px);\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-title-4, 1.125rem);\n font-weight: var(--gnome-font-weight-bold, 700);\n line-height: var(--gnome-line-height-title, 1.3);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n text-align: center;\n}\n\n/* ─── Content ───────────────────────────────────────────────────────────────── */\n\n.content {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-4, 24px);\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .backdrop {\n background-color: rgba(0, 0, 0, 0.65);\n }\n\n .sheet {\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #242424));\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.45),\n 0 0 0 1px rgba(255, 255, 255, 0.06);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .backdrop,\n .sheet,\n .backdrop.closing,\n .sheet.entering,\n .sheet.closing,\n .sheet.dragging {\n animation: none;\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
var e = {
|
|
2
|
-
backdrop: "
|
|
3
|
-
"backdrop-in": "_backdrop-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
backdrop: "_backdrop_mrs02_3",
|
|
3
|
+
"backdrop-in": "_backdrop-in_mrs02_1",
|
|
4
|
+
closing: "_closing_mrs02_19",
|
|
5
|
+
"backdrop-out": "_backdrop-out_mrs02_1",
|
|
6
|
+
sheet: "_sheet_mrs02_43",
|
|
7
|
+
entering: "_entering_mrs02_61",
|
|
8
|
+
"sheet-in": "_sheet-in_mrs02_1",
|
|
9
|
+
"sheet-out": "_sheet-out_mrs02_1",
|
|
10
|
+
dragging: "_dragging_mrs02_70",
|
|
11
|
+
handle: "_handle_mrs02_94",
|
|
12
|
+
handleBar: "_handleBar_mrs02_108",
|
|
13
|
+
title: "_title_mrs02_119",
|
|
14
|
+
content: "_content_mrs02_132"
|
|
10
15
|
};
|
|
11
16
|
//#endregion
|
|
12
17
|
export { e as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomSheet.module.css.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.module.css"],"sourcesContent":["/* ─── Backdrop ──────────────────────────────────────────────────────────────── */\n\n.backdrop {\n position: fixed;\n inset: 0;\n z-index: 10000;\n\n display: flex;\n align-items: flex-end;\n justify-content: center;\n\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n\n animation: backdrop-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes backdrop-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ─── Sheet ─────────────────────────────────────────────────────────────────── */\n\n.sheet {\n width: min(560px, 100vw);\n max-height: 90dvh;\n overflow-y: auto;\n\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #fafafa));\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n\n border-radius: var(--gnome-radius-xl, 16px) var(--gnome-radius-xl, 16px) 0 0;\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.18),\n 0 0 0 1px rgba(0, 0, 0, 0.06);\n\n animation: sheet-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes sheet-in {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n/* ─── Handle bar ────────────────────────────────────────────────────────────── */\n\n.handle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--gnome-space-2, 12px) 0 var(--gnome-space-1, 6px);\n}\n\n.handleBar {\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background-color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n opacity: 0.2;\n}\n\n/* ─── Title ─────────────────────────────────────────────────────────────────── */\n\n.title {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-2, 12px);\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-title-4, 1.125rem);\n font-weight: var(--gnome-font-weight-bold, 700);\n line-height: var(--gnome-line-height-title, 1.3);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n text-align: center;\n}\n\n/* ─── Content ───────────────────────────────────────────────────────────────── */\n\n.content {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-4, 24px);\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .backdrop {\n background-color: rgba(0, 0, 0, 0.65);\n }\n\n .sheet {\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #242424));\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.45),\n 0 0 0 1px rgba(255, 255, 255, 0.06);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .backdrop,\n .sheet {\n animation: none;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"BottomSheet.module.css.js","names":[],"sources":["../../../src/components/BottomSheet/BottomSheet.module.css"],"sourcesContent":["/* ─── Backdrop ──────────────────────────────────────────────────────────────── */\n\n.backdrop {\n position: fixed;\n inset: 0;\n z-index: 10000;\n\n display: flex;\n align-items: flex-end;\n justify-content: center;\n\n background-color: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n\n animation: backdrop-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n.backdrop.closing {\n animation: backdrop-out var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n@keyframes backdrop-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n@keyframes backdrop-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n/* ─── Sheet ─────────────────────────────────────────────────────────────────── */\n\n.sheet {\n width: min(560px, 100vw);\n max-height: 90dvh;\n overflow-y: auto;\n\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #fafafa));\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n\n border-radius: var(--gnome-radius-xl, 16px) var(--gnome-radius-xl, 16px) 0 0;\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.18),\n 0 0 0 1px rgba(0, 0, 0, 0.06);\n\n /* Snap-back transition after releasing a partial drag */\n transition: transform 200ms var(--gnome-easing-default, ease);\n will-change: transform;\n}\n\n.sheet.entering {\n animation: sheet-in var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n.sheet.closing {\n animation: sheet-out var(--gnome-duration-normal, 200ms) var(--gnome-easing-default, ease) both;\n}\n\n/* Disable transition while actively dragging so the sheet follows the pointer instantly */\n.sheet.dragging {\n transition: none;\n}\n\n@keyframes sheet-in {\n from {\n transform: translateY(100%);\n }\n to {\n transform: translateY(0);\n }\n}\n\n@keyframes sheet-out {\n from {\n transform: translateY(0);\n }\n to {\n transform: translateY(100%);\n }\n}\n\n/* ─── Handle bar ────────────────────────────────────────────────────────────── */\n\n.handle {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--gnome-space-2, 12px) 0 var(--gnome-space-1, 6px);\n cursor: grab;\n /* Prevents the browser from hijacking the pointer for scroll while dragging */\n touch-action: none;\n}\n\n.handle:active {\n cursor: grabbing;\n}\n\n.handleBar {\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background-color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n opacity: 0.2;\n pointer-events: none;\n}\n\n/* ─── Title ─────────────────────────────────────────────────────────────────── */\n\n.title {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-2, 12px);\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-title-4, 1.125rem);\n font-weight: var(--gnome-font-weight-bold, 700);\n line-height: var(--gnome-line-height-title, 1.3);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n text-align: center;\n}\n\n/* ─── Content ───────────────────────────────────────────────────────────────── */\n\n.content {\n padding: 0 var(--gnome-space-4, 24px) var(--gnome-space-4, 24px);\n}\n\n/* ─── Dark mode ─────────────────────────────────────────────────────────────── */\n\n@media (prefers-color-scheme: dark) {\n .backdrop {\n background-color: rgba(0, 0, 0, 0.65);\n }\n\n .sheet {\n background-color: var(--gnome-dialog-bg-color, var(--gnome-window-bg-color, #242424));\n box-shadow:\n 0 -4px 24px rgba(0, 0, 0, 0.45),\n 0 0 0 1px rgba(255, 255, 255, 0.06);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .backdrop,\n .sheet,\n .backdrop.closing,\n .sheet.entering,\n .sheet.closing,\n .sheet.dragging {\n animation: none;\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={row:`
|
|
1
|
+
var e={row:`_row_14iw1_3`,focused:`_focused_14iw1_16`,disabled:`_disabled_14iw1_25`,leading:`_leading_14iw1_33`,trailing:`_trailing_14iw1_40`,fieldWrap:`_fieldWrap_14iw1_49`,label:`_label_14iw1_61`,labelFloated:`_labelFloated_14iw1_82`,input:`_input_14iw1_91`,inputFloated:`_inputFloated_14iw1_114`};exports.default=e;
|
|
2
2
|
//# sourceMappingURL=EntryRow.module.css.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntryRow.module.css.cjs","names":[],"sources":["../../../src/components/EntryRow/EntryRow.module.css"],"sourcesContent":["/* ─── Row container ─────────────────────────────────────────────────────────── */\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--gnome-space-2, 12px);\n padding: 0 var(--gnome-space-4, 24px);\n min-height:
|
|
1
|
+
{"version":3,"file":"EntryRow.module.css.cjs","names":[],"sources":["../../../src/components/EntryRow/EntryRow.module.css"],"sourcesContent":["/* ─── Row container ─────────────────────────────────────────────────────────── */\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--gnome-space-2, 12px);\n padding: 0 var(--gnome-space-4, 24px);\n min-height: 56px;\n width: 100%;\n cursor: text;\n color: var(--gnome-card-fg-color, rgba(0, 0, 0, 0.8));\n\n transition: box-shadow var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n.focused {\n box-shadow:\n inset 0 0 0 var(--gnome-focus-ring-offset, 2px) var(--gnome-window-bg-color, #fafafa),\n inset 0 0 0 calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px))\n var(--gnome-focus-ring-color, #3584e4);\n}\n\n/* ─── Disabled ──────────────────────────────────────────────────────────────── */\n\n.disabled {\n opacity: var(--gnome-opacity-disabled, 0.5);\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* ─── Leading / trailing ────────────────────────────────────────────────────── */\n\n.leading {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n}\n\n.trailing {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n gap: var(--gnome-space-1, 6px);\n}\n\n/* ─── Field wrap ────────────────────────────────────────────────────────────── */\n\n.fieldWrap {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: center;\n flex: 1;\n min-width: 0;\n min-height: 56px;\n}\n\n/* ─── Floating label ────────────────────────────────────────────────────────── */\n\n.label {\n position: absolute;\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-body, 1rem);\n line-height: var(--gnome-line-height-body, 1.5);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.55));\n opacity: var(--gnome-opacity-dim, 0.55);\n\n transition:\n top var(--gnome-duration-fast) var(--gnome-easing-default),\n transform var(--gnome-duration-fast) var(--gnome-easing-default),\n font-size var(--gnome-duration-fast) var(--gnome-easing-default),\n opacity var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n/* When floated (focused or has value) the label moves up */\n.labelFloated {\n top: 6px;\n transform: translateY(0);\n font-size: var(--gnome-font-size-caption, 0.75rem);\n opacity: 0.7;\n}\n\n/* ─── Input field ───────────────────────────────────────────────────────────── */\n\n.input {\n appearance: none;\n background: transparent;\n border: none;\n outline: none;\n padding: 0;\n margin: 0;\n width: 100%;\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-body, 1rem);\n font-weight: var(--gnome-font-weight-normal, 400);\n line-height: var(--gnome-line-height-body, 1.5);\n color: var(--gnome-card-fg-color, rgba(0, 0, 0, 0.8));\n\n /* Hide until floated — the label is the placeholder */\n opacity: 0;\n padding-top: 24px;\n padding-bottom: 4px;\n\n transition: opacity var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n.inputFloated {\n opacity: 1;\n}\n\n.input:disabled {\n cursor: not-allowed;\n}\n\n/* ─── High contrast ─────────────────────────────────────────────────────────── */\n\n@media (prefers-contrast: more) {\n .focused {\n box-shadow:\n inset 0 0 0 var(--gnome-focus-ring-offset, 2px) var(--gnome-window-bg-color, #fafafa),\n inset 0 0 0 calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px))\n var(--gnome-focus-ring-color, #3584e4),\n inset 0 0 0\n calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px) + 1px)\n var(--gnome-window-bg-color, #fafafa);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .row,\n .label,\n .input {\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
var e = {
|
|
2
|
-
row: "
|
|
3
|
-
focused: "
|
|
4
|
-
disabled: "
|
|
5
|
-
leading: "
|
|
6
|
-
trailing: "
|
|
7
|
-
fieldWrap: "
|
|
8
|
-
label: "
|
|
9
|
-
labelFloated: "
|
|
10
|
-
input: "
|
|
11
|
-
inputFloated: "
|
|
2
|
+
row: "_row_14iw1_3",
|
|
3
|
+
focused: "_focused_14iw1_16",
|
|
4
|
+
disabled: "_disabled_14iw1_25",
|
|
5
|
+
leading: "_leading_14iw1_33",
|
|
6
|
+
trailing: "_trailing_14iw1_40",
|
|
7
|
+
fieldWrap: "_fieldWrap_14iw1_49",
|
|
8
|
+
label: "_label_14iw1_61",
|
|
9
|
+
labelFloated: "_labelFloated_14iw1_82",
|
|
10
|
+
input: "_input_14iw1_91",
|
|
11
|
+
inputFloated: "_inputFloated_14iw1_114"
|
|
12
12
|
};
|
|
13
13
|
//#endregion
|
|
14
14
|
export { e as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntryRow.module.css.js","names":[],"sources":["../../../src/components/EntryRow/EntryRow.module.css"],"sourcesContent":["/* ─── Row container ─────────────────────────────────────────────────────────── */\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--gnome-space-2, 12px);\n padding: 0 var(--gnome-space-4, 24px);\n min-height:
|
|
1
|
+
{"version":3,"file":"EntryRow.module.css.js","names":[],"sources":["../../../src/components/EntryRow/EntryRow.module.css"],"sourcesContent":["/* ─── Row container ─────────────────────────────────────────────────────────── */\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--gnome-space-2, 12px);\n padding: 0 var(--gnome-space-4, 24px);\n min-height: 56px;\n width: 100%;\n cursor: text;\n color: var(--gnome-card-fg-color, rgba(0, 0, 0, 0.8));\n\n transition: box-shadow var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n.focused {\n box-shadow:\n inset 0 0 0 var(--gnome-focus-ring-offset, 2px) var(--gnome-window-bg-color, #fafafa),\n inset 0 0 0 calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px))\n var(--gnome-focus-ring-color, #3584e4);\n}\n\n/* ─── Disabled ──────────────────────────────────────────────────────────────── */\n\n.disabled {\n opacity: var(--gnome-opacity-disabled, 0.5);\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* ─── Leading / trailing ────────────────────────────────────────────────────── */\n\n.leading {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.8));\n}\n\n.trailing {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n gap: var(--gnome-space-1, 6px);\n}\n\n/* ─── Field wrap ────────────────────────────────────────────────────────────── */\n\n.fieldWrap {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: center;\n flex: 1;\n min-width: 0;\n min-height: 56px;\n}\n\n/* ─── Floating label ────────────────────────────────────────────────────────── */\n\n.label {\n position: absolute;\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n pointer-events: none;\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-body, 1rem);\n line-height: var(--gnome-line-height-body, 1.5);\n color: var(--gnome-window-fg-color, rgba(0, 0, 0, 0.55));\n opacity: var(--gnome-opacity-dim, 0.55);\n\n transition:\n top var(--gnome-duration-fast) var(--gnome-easing-default),\n transform var(--gnome-duration-fast) var(--gnome-easing-default),\n font-size var(--gnome-duration-fast) var(--gnome-easing-default),\n opacity var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n/* When floated (focused or has value) the label moves up */\n.labelFloated {\n top: 6px;\n transform: translateY(0);\n font-size: var(--gnome-font-size-caption, 0.75rem);\n opacity: 0.7;\n}\n\n/* ─── Input field ───────────────────────────────────────────────────────────── */\n\n.input {\n appearance: none;\n background: transparent;\n border: none;\n outline: none;\n padding: 0;\n margin: 0;\n width: 100%;\n\n font-family: var(--gnome-font-family);\n font-size: var(--gnome-font-size-body, 1rem);\n font-weight: var(--gnome-font-weight-normal, 400);\n line-height: var(--gnome-line-height-body, 1.5);\n color: var(--gnome-card-fg-color, rgba(0, 0, 0, 0.8));\n\n /* Hide until floated — the label is the placeholder */\n opacity: 0;\n padding-top: 24px;\n padding-bottom: 4px;\n\n transition: opacity var(--gnome-duration-fast) var(--gnome-easing-default);\n}\n\n.inputFloated {\n opacity: 1;\n}\n\n.input:disabled {\n cursor: not-allowed;\n}\n\n/* ─── High contrast ─────────────────────────────────────────────────────────── */\n\n@media (prefers-contrast: more) {\n .focused {\n box-shadow:\n inset 0 0 0 var(--gnome-focus-ring-offset, 2px) var(--gnome-window-bg-color, #fafafa),\n inset 0 0 0 calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px))\n var(--gnome-focus-ring-color, #3584e4),\n inset 0 0 0\n calc(var(--gnome-focus-ring-offset, 2px) + var(--gnome-focus-ring-width, 3px) + 1px)\n var(--gnome-window-bg-color, #fafafa);\n }\n}\n\n/* ─── Reduced motion ────────────────────────────────────────────────────────── */\n\n@media (prefers-reduced-motion: reduce) {\n .row,\n .label,\n .input {\n transition: none;\n }\n}\n"],"mappings":""}
|