@evinvest/uikit 0.15.1 → 0.16.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 +13 -3
- package/dist/index.d.ts +20 -7
- package/dist/index.js +189 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/tokens.css +135 -1
package/README.md
CHANGED
|
@@ -215,9 +215,19 @@ measuring needs host-only `web-sys`). Known gaps:
|
|
|
215
215
|
onto an arbitrary child (no `Slot`), so it publishes them as a
|
|
216
216
|
`FormControlContext` that `Input`/`Textarea` consume; wrap a bare element and
|
|
217
217
|
you wire them yourself.
|
|
218
|
-
- **resizable / carousel
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
- **resizable / carousel:** pointer-drag physics are TS-only (keyboard in Rust
|
|
219
|
+
for resizable; prev/next + keyboard for carousel). Embla momentum is not
|
|
220
|
+
reproduced.
|
|
221
|
+
- **drawer:** the Vaul-style enter/exit motion is shared by both ports via
|
|
222
|
+
`motion.css` (inlined into `tokens.css`), keyed on `data-slot` +
|
|
223
|
+
`data-vaul-drawer-direction` + `data-state`; the panel stays mounted on close
|
|
224
|
+
until its exit `transitionend`. Drag-to-dismiss (Vaul's pointer physics, from
|
|
225
|
+
any of the four edges; opt a region out with `data-vaul-no-drag`) is TS-only;
|
|
226
|
+
Rust dismisses on scrim click / Escape / `DrawerClose`. The panel is
|
|
227
|
+
`touch-action: none` so a touch never turns into a page pan, which also means
|
|
228
|
+
the panel itself must not scroll: the kit renders children inside a
|
|
229
|
+
`data-slot="drawer-body"` scroller (`overflow-y-auto`), so cap the sheet with
|
|
230
|
+
`max-h-*` on `DrawerContent` and let the body scroll by itself.
|
|
221
231
|
- **sidebar:** the mobile-sheet integration, cookie persistence, and keyboard
|
|
222
232
|
shortcut are omitted.
|
|
223
233
|
- **brand chrome (header / footer / status pages):** TS routes links through an
|
package/dist/index.d.ts
CHANGED
|
@@ -168,9 +168,9 @@ declare function mergeRefs<T>(...refs: Array<React.Ref<T> | undefined>): React.R
|
|
|
168
168
|
|
|
169
169
|
declare const alertVariants: {
|
|
170
170
|
readonly neutral: "bg-card text-ink";
|
|
171
|
-
readonly destructive: "text-accent-error bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
172
|
-
readonly success: "text-positive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
173
|
-
readonly info: "text-accent-info bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
171
|
+
readonly destructive: "text-accent-error bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid";
|
|
172
|
+
readonly success: "text-positive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid";
|
|
173
|
+
readonly info: "text-accent-info bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid";
|
|
174
174
|
};
|
|
175
175
|
type AlertVariant = keyof typeof alertVariants;
|
|
176
176
|
|
|
@@ -1242,10 +1242,10 @@ declare function SheetTitle({ className, ...props }: React.ComponentProps<"h2">)
|
|
|
1242
1242
|
declare function SheetDescription({ className, ...props }: React.ComponentProps<"p">): React.JSX.Element;
|
|
1243
1243
|
|
|
1244
1244
|
declare const drawerDirectionClasses: {
|
|
1245
|
-
readonly bottom: "
|
|
1246
|
-
readonly top: "
|
|
1247
|
-
readonly left: "
|
|
1248
|
-
readonly right: "
|
|
1245
|
+
readonly bottom: "inset-x-0 bottom-0 mt-24 max-h-[80vh] flex-col rounded-t-lg border-b-0";
|
|
1246
|
+
readonly top: "inset-x-0 top-0 mb-24 max-h-[80vh] flex-col rounded-b-lg border-t-0";
|
|
1247
|
+
readonly left: "inset-y-0 left-0 w-3/4 flex-row border-r sm:max-w-sm";
|
|
1248
|
+
readonly right: "inset-y-0 right-0 w-3/4 flex-row border-l sm:max-w-sm";
|
|
1249
1249
|
};
|
|
1250
1250
|
type DrawerDirection = keyof typeof drawerDirectionClasses;
|
|
1251
1251
|
|
|
@@ -1265,7 +1265,20 @@ interface DrawerCloseProps extends React.ComponentProps<"button"> {
|
|
|
1265
1265
|
asChild?: boolean;
|
|
1266
1266
|
}
|
|
1267
1267
|
declare function DrawerClose({ asChild, onClick, ...props }: DrawerCloseProps): React.JSX.Element;
|
|
1268
|
+
/**
|
|
1269
|
+
* Standalone scrim, redundant with the one {@link DrawerContent} renders (as in
|
|
1270
|
+
* shadcn). Mounted only while open; the animated exit lives on the content's
|
|
1271
|
+
* own scrim.
|
|
1272
|
+
*/
|
|
1268
1273
|
declare function DrawerOverlay({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element | null;
|
|
1274
|
+
/**
|
|
1275
|
+
* The panel plus its scrim. Presence outlives `open`: once it turns false the
|
|
1276
|
+
* panel flips to `data-state="closed"` and is unmounted when its exit
|
|
1277
|
+
* `transform` transition ends (or the fallback timer fires). Re-opening
|
|
1278
|
+
* mid-exit just flips the state back and the same transition carries the
|
|
1279
|
+
* panel home. Drag-to-dismiss is TS-only pointer physics; opt a region out
|
|
1280
|
+
* with `data-vaul-no-drag`.
|
|
1281
|
+
*/
|
|
1269
1282
|
declare function DrawerContent({ className, children, ...props }: React.ComponentProps<"div">): React.JSX.Element | null;
|
|
1270
1283
|
declare function DrawerHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
1271
1284
|
declare function DrawerFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -334,9 +334,9 @@ import "react";
|
|
|
334
334
|
var ALERT_BASE = "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current";
|
|
335
335
|
var alertVariants = {
|
|
336
336
|
"neutral": "bg-card text-ink",
|
|
337
|
-
"destructive": "text-accent-error bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
338
|
-
"success": "text-positive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
339
|
-
"info": "text-accent-info bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-
|
|
337
|
+
"destructive": "text-accent-error bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid",
|
|
338
|
+
"success": "text-positive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid",
|
|
339
|
+
"info": "text-accent-info bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-ink-mid"
|
|
340
340
|
};
|
|
341
341
|
var ALERT_TITLE = "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight";
|
|
342
342
|
var ALERT_DESCRIPTION = "text-ink-soft col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed";
|
|
@@ -5891,15 +5891,16 @@ function SheetDescription({ className, ...props }) {
|
|
|
5891
5891
|
import * as React62 from "react";
|
|
5892
5892
|
|
|
5893
5893
|
// src/generated/drawer.ts
|
|
5894
|
-
var DRAWER_CONTENT_BASE = "bg-background
|
|
5894
|
+
var DRAWER_CONTENT_BASE = "bg-background fixed z-50 flex h-auto border";
|
|
5895
5895
|
var drawerDirectionClasses = {
|
|
5896
|
-
"bottom": "
|
|
5897
|
-
"top": "
|
|
5898
|
-
"left": "
|
|
5899
|
-
"right": "
|
|
5896
|
+
"bottom": "inset-x-0 bottom-0 mt-24 max-h-[80vh] flex-col rounded-t-lg border-b-0",
|
|
5897
|
+
"top": "inset-x-0 top-0 mb-24 max-h-[80vh] flex-col rounded-b-lg border-t-0",
|
|
5898
|
+
"left": "inset-y-0 left-0 w-3/4 flex-row border-r sm:max-w-sm",
|
|
5899
|
+
"right": "inset-y-0 right-0 w-3/4 flex-row border-l sm:max-w-sm"
|
|
5900
5900
|
};
|
|
5901
|
-
var DRAWER_OVERLAY = "
|
|
5902
|
-
var DRAWER_HANDLE = "bg-muted mx-auto mt-4
|
|
5901
|
+
var DRAWER_OVERLAY = "fixed inset-0 z-50 bg-black/50";
|
|
5902
|
+
var DRAWER_HANDLE = "bg-muted mx-auto mt-4 h-2 w-[100px] shrink-0 rounded-full";
|
|
5903
|
+
var DRAWER_BODY = "flex min-h-0 flex-1 flex-col overflow-y-auto";
|
|
5903
5904
|
var DRAWER_HEADER = "flex flex-col gap-0.5 p-4 text-center sm:gap-1.5 sm:text-left";
|
|
5904
5905
|
var DRAWER_FOOTER = "mt-auto flex flex-col gap-2 p-4";
|
|
5905
5906
|
var DRAWER_TITLE = "text-ink font-semibold";
|
|
@@ -5907,6 +5908,10 @@ var DRAWER_DESCRIPTION = "text-ink-soft text-sm";
|
|
|
5907
5908
|
|
|
5908
5909
|
// src/components/drawer.tsx
|
|
5909
5910
|
import { jsx as jsx52, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5911
|
+
var CLOSE_THRESHOLD = 0.25;
|
|
5912
|
+
var VELOCITY_THRESHOLD = 0.4;
|
|
5913
|
+
var DRAG_AFTER_OPEN_MS = 500;
|
|
5914
|
+
var EXIT_FALLBACK_MS = 600;
|
|
5910
5915
|
var DrawerContext = React62.createContext(null);
|
|
5911
5916
|
function useDrawer() {
|
|
5912
5917
|
const ctx = React62.useContext(DrawerContext);
|
|
@@ -5971,16 +5976,169 @@ function DrawerOverlay({ className, ...props }) {
|
|
|
5971
5976
|
}
|
|
5972
5977
|
);
|
|
5973
5978
|
}
|
|
5979
|
+
var EDGE_SIGN = {
|
|
5980
|
+
bottom: 1,
|
|
5981
|
+
top: -1,
|
|
5982
|
+
right: 1,
|
|
5983
|
+
left: -1
|
|
5984
|
+
};
|
|
5985
|
+
function isVertical(direction) {
|
|
5986
|
+
return direction === "bottom" || direction === "top";
|
|
5987
|
+
}
|
|
5988
|
+
function translateAlong(direction, px) {
|
|
5989
|
+
return isVertical(direction) ? `translate3d(0, ${px}px, 0)` : `translate3d(${px}px, 0, 0)`;
|
|
5990
|
+
}
|
|
5991
|
+
function dampen(px) {
|
|
5992
|
+
return Math.max(8 * (Math.log(px + 1) - 2), 0);
|
|
5993
|
+
}
|
|
5994
|
+
function shouldDrag(target, panel, direction, towardsEdge) {
|
|
5995
|
+
if (!(target instanceof Element)) return false;
|
|
5996
|
+
if (target.tagName === "SELECT") return false;
|
|
5997
|
+
if (target.closest("[data-vaul-no-drag]")) return false;
|
|
5998
|
+
if (!isVertical(direction)) return true;
|
|
5999
|
+
if (!towardsEdge) return false;
|
|
6000
|
+
const selection = window.getSelection?.()?.toString();
|
|
6001
|
+
if (selection && selection.length > 0) return false;
|
|
6002
|
+
let el = target;
|
|
6003
|
+
while (el && el !== panel) {
|
|
6004
|
+
if (el.scrollHeight > el.clientHeight && el.scrollTop > 0) return false;
|
|
6005
|
+
el = el.parentElement;
|
|
6006
|
+
}
|
|
6007
|
+
return true;
|
|
6008
|
+
}
|
|
6009
|
+
function useDrawerDrag(opts) {
|
|
6010
|
+
const { panelRef, scrimRef, direction, open, present, openedAtRef, onClose } = opts;
|
|
6011
|
+
const dragRef = React62.useRef(null);
|
|
6012
|
+
React62.useEffect(() => {
|
|
6013
|
+
if (!present) return;
|
|
6014
|
+
const panel = panelRef.current;
|
|
6015
|
+
if (!panel) return;
|
|
6016
|
+
const onTouchMove = (e) => {
|
|
6017
|
+
if (dragRef.current?.allowed) e.preventDefault();
|
|
6018
|
+
};
|
|
6019
|
+
panel.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
6020
|
+
return () => panel.removeEventListener("touchmove", onTouchMove);
|
|
6021
|
+
}, [present, panelRef]);
|
|
6022
|
+
const axisPos = (e) => isVertical(direction) ? e.clientY : e.clientX;
|
|
6023
|
+
const onPointerDown = (e) => {
|
|
6024
|
+
const panel = panelRef.current;
|
|
6025
|
+
if (!panel || e.button > 0 || !open || dragRef.current) return;
|
|
6026
|
+
const target = e.target;
|
|
6027
|
+
if (target.closest('[data-slot="drawer-close"]')) return;
|
|
6028
|
+
if (!panel.contains(target)) return;
|
|
6029
|
+
const rect = panel.getBoundingClientRect();
|
|
6030
|
+
dragRef.current = {
|
|
6031
|
+
pointerId: e.pointerId,
|
|
6032
|
+
target,
|
|
6033
|
+
start: axisPos(e),
|
|
6034
|
+
time: Date.now(),
|
|
6035
|
+
size: isVertical(direction) ? rect.height : rect.width,
|
|
6036
|
+
allowed: null,
|
|
6037
|
+
delta: 0
|
|
6038
|
+
};
|
|
6039
|
+
try {
|
|
6040
|
+
target.setPointerCapture?.(e.pointerId);
|
|
6041
|
+
} catch {
|
|
6042
|
+
}
|
|
6043
|
+
};
|
|
6044
|
+
const onPointerMove = (e) => {
|
|
6045
|
+
const drag = dragRef.current;
|
|
6046
|
+
const panel = panelRef.current;
|
|
6047
|
+
if (!drag || !panel) return;
|
|
6048
|
+
const delta = (axisPos(e) - drag.start) * EDGE_SIGN[direction];
|
|
6049
|
+
drag.delta = delta;
|
|
6050
|
+
if (!drag.allowed) {
|
|
6051
|
+
if (Date.now() - openedAtRef.current < DRAG_AFTER_OPEN_MS) return;
|
|
6052
|
+
if (!shouldDrag(drag.target, panel, direction, delta > 0)) return;
|
|
6053
|
+
drag.allowed = true;
|
|
6054
|
+
panel.setAttribute("data-dragging", "true");
|
|
6055
|
+
scrimRef.current?.setAttribute("data-dragging", "true");
|
|
6056
|
+
}
|
|
6057
|
+
const scrim = scrimRef.current;
|
|
6058
|
+
if (delta < 0) {
|
|
6059
|
+
panel.style.transform = translateAlong(direction, -dampen(-delta) * EDGE_SIGN[direction]);
|
|
6060
|
+
if (scrim) scrim.style.opacity = "1";
|
|
6061
|
+
return;
|
|
6062
|
+
}
|
|
6063
|
+
panel.style.transform = translateAlong(direction, delta * EDGE_SIGN[direction]);
|
|
6064
|
+
if (scrim) {
|
|
6065
|
+
scrim.style.opacity = `${Math.min(1, Math.max(0, 1 - delta / drag.size))}`;
|
|
6066
|
+
}
|
|
6067
|
+
};
|
|
6068
|
+
const endGesture = (e, cancelled) => {
|
|
6069
|
+
const drag = dragRef.current;
|
|
6070
|
+
const panel = panelRef.current;
|
|
6071
|
+
if (!drag || !panel || e.pointerId !== drag.pointerId) return;
|
|
6072
|
+
dragRef.current = null;
|
|
6073
|
+
try {
|
|
6074
|
+
drag.target.releasePointerCapture?.(drag.pointerId);
|
|
6075
|
+
} catch {
|
|
6076
|
+
}
|
|
6077
|
+
if (!drag.allowed) return;
|
|
6078
|
+
panel.removeAttribute("data-dragging");
|
|
6079
|
+
panel.style.transform = "";
|
|
6080
|
+
const scrim = scrimRef.current;
|
|
6081
|
+
if (scrim) {
|
|
6082
|
+
scrim.removeAttribute("data-dragging");
|
|
6083
|
+
scrim.style.opacity = "";
|
|
6084
|
+
}
|
|
6085
|
+
if (cancelled || drag.delta <= 0) return;
|
|
6086
|
+
const dt = Date.now() - drag.time;
|
|
6087
|
+
const velocity = dt > 0 ? drag.delta / dt : 0;
|
|
6088
|
+
if (velocity > VELOCITY_THRESHOLD || drag.delta >= drag.size * CLOSE_THRESHOLD) {
|
|
6089
|
+
onClose();
|
|
6090
|
+
}
|
|
6091
|
+
};
|
|
6092
|
+
return {
|
|
6093
|
+
onPointerDown,
|
|
6094
|
+
onPointerMove,
|
|
6095
|
+
onPointerUp: (e) => endGesture(e, false),
|
|
6096
|
+
onPointerCancel: (e) => endGesture(e, true)
|
|
6097
|
+
};
|
|
6098
|
+
}
|
|
5974
6099
|
function DrawerContent({ className, children, ...props }) {
|
|
5975
6100
|
const { open, setOpen, direction } = useDrawer();
|
|
6101
|
+
const [present, setPresent] = React62.useState(open);
|
|
6102
|
+
if (open && !present) setPresent(true);
|
|
6103
|
+
const closing = present && !open;
|
|
5976
6104
|
const scopeRef = useFocusScope(open);
|
|
5977
|
-
|
|
6105
|
+
const panelRef = React62.useRef(null);
|
|
6106
|
+
const scrimRef = React62.useRef(null);
|
|
6107
|
+
const openedAtRef = React62.useRef(0);
|
|
6108
|
+
React62.useEffect(() => {
|
|
6109
|
+
if (open) openedAtRef.current = Date.now();
|
|
6110
|
+
}, [open]);
|
|
6111
|
+
React62.useEffect(() => {
|
|
6112
|
+
if (!open) return;
|
|
6113
|
+
const prev = document.body.style.overflow;
|
|
6114
|
+
document.body.style.overflow = "hidden";
|
|
6115
|
+
return () => {
|
|
6116
|
+
document.body.style.overflow = prev;
|
|
6117
|
+
};
|
|
6118
|
+
}, [open]);
|
|
6119
|
+
React62.useEffect(() => {
|
|
6120
|
+
if (!closing) return;
|
|
6121
|
+
const id = setTimeout(() => setPresent(false), EXIT_FALLBACK_MS);
|
|
6122
|
+
return () => clearTimeout(id);
|
|
6123
|
+
}, [closing]);
|
|
6124
|
+
const drag = useDrawerDrag({
|
|
6125
|
+
panelRef,
|
|
6126
|
+
scrimRef,
|
|
6127
|
+
direction,
|
|
6128
|
+
open,
|
|
6129
|
+
present,
|
|
6130
|
+
openedAtRef,
|
|
6131
|
+
onClose: () => setOpen(false)
|
|
6132
|
+
});
|
|
6133
|
+
if (!present) return null;
|
|
6134
|
+
const state = closing ? "closed" : "open";
|
|
5978
6135
|
return /* @__PURE__ */ jsxs22(Portal, { children: [
|
|
5979
6136
|
/* @__PURE__ */ jsx52(
|
|
5980
6137
|
"div",
|
|
5981
6138
|
{
|
|
6139
|
+
ref: scrimRef,
|
|
5982
6140
|
"data-slot": "drawer-overlay",
|
|
5983
|
-
"data-state":
|
|
6141
|
+
"data-state": state,
|
|
5984
6142
|
className: DRAWER_OVERLAY,
|
|
5985
6143
|
onClick: () => setOpen(false)
|
|
5986
6144
|
}
|
|
@@ -5991,12 +6149,21 @@ function DrawerContent({ className, children, ...props }) {
|
|
|
5991
6149
|
role: "dialog",
|
|
5992
6150
|
"aria-modal": "true",
|
|
5993
6151
|
"data-slot": "drawer-content",
|
|
5994
|
-
"data-state":
|
|
6152
|
+
"data-state": state,
|
|
5995
6153
|
"data-vaul-drawer-direction": direction,
|
|
5996
|
-
ref: mergeRefs(scopeRef),
|
|
6154
|
+
ref: mergeRefs(scopeRef, panelRef),
|
|
5997
6155
|
onKeyDown: (e) => {
|
|
5998
6156
|
if (e.key === "Escape") setOpen(false);
|
|
5999
6157
|
},
|
|
6158
|
+
onTransitionEnd: (e) => {
|
|
6159
|
+
if (closing && e.propertyName === "transform" && e.target === e.currentTarget) {
|
|
6160
|
+
setPresent(false);
|
|
6161
|
+
}
|
|
6162
|
+
},
|
|
6163
|
+
onPointerDown: drag.onPointerDown,
|
|
6164
|
+
onPointerMove: drag.onPointerMove,
|
|
6165
|
+
onPointerUp: drag.onPointerUp,
|
|
6166
|
+
onPointerCancel: drag.onPointerCancel,
|
|
6000
6167
|
className: cn(DRAWER_CONTENT_BASE, drawerDirectionClasses[direction], className),
|
|
6001
6168
|
...props,
|
|
6002
6169
|
children: [
|
|
@@ -6007,7 +6174,14 @@ function DrawerContent({ className, children, ...props }) {
|
|
|
6007
6174
|
className: DRAWER_HANDLE
|
|
6008
6175
|
}
|
|
6009
6176
|
) : null,
|
|
6010
|
-
|
|
6177
|
+
/* @__PURE__ */ jsx52(
|
|
6178
|
+
"div",
|
|
6179
|
+
{
|
|
6180
|
+
"data-slot": "drawer-body",
|
|
6181
|
+
className: DRAWER_BODY,
|
|
6182
|
+
children
|
|
6183
|
+
}
|
|
6184
|
+
)
|
|
6011
6185
|
]
|
|
6012
6186
|
}
|
|
6013
6187
|
)
|