@passui/react 0.1.44 → 0.1.46
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 +57 -46
- package/dist/types/src/components/accordion/accordion.d.ts +1 -1
- package/dist/types/src/components/breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +1 -1
- package/dist/types/src/components/popover/anchored-surface.d.ts +5 -1
- package/dist/types/src/components/popover/index.d.ts +41 -0
- package/dist/types/src/components/popover/popover-content.d.ts +32 -0
- package/dist/types/src/components/popover/popover-root.d.ts +22 -0
- package/dist/types/src/components/popover/popover-trigger.d.ts +23 -0
- package/dist/types/src/components/stepper/rolling-digit.d.ts +1 -1
- package/dist/types/src/components/table/table.d.ts +1 -1
- package/dist/types/src/components/view-controller/view-controller.d.ts +2 -2
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/machines/popover.machine.d.ts +30 -0
- package/package.json +307 -307
- package/src/appearance/index.ts +2 -2
- package/src/appearance/platform.tsx +76 -60
- package/src/appearance/theme.tsx +409 -377
- package/src/components/accordion/accordion.tsx +58 -49
- package/src/components/ambient/ambient.tsx +25 -25
- package/src/components/ambient/index.ts +1 -1
- package/src/components/aspect-ratio/aspect-ratio.tsx +21 -16
- package/src/components/breadcrumb/breadcrumb.tsx +63 -57
- package/src/components/button/button-styles.ts +39 -32
- package/src/components/button/button.tsx +91 -84
- package/src/components/button/icon-button.tsx +27 -25
- package/src/components/button/pending-spinner.tsx +8 -8
- package/src/components/button/use-pending-indicator.ts +11 -11
- package/src/components/chip/chip.tsx +35 -30
- package/src/components/code-block/code-block.tsx +40 -39
- package/src/components/combo-box/combo-box.tsx +5 -5
- package/src/components/command/command.tsx +124 -94
- package/src/components/compact-date-picker/calendar-month.ts +75 -53
- package/src/components/compact-date-picker/compact-date-picker.tsx +308 -289
- package/src/components/compact-time-picker/compact-time-picker.tsx +288 -281
- package/src/components/compact-time-picker/time-value.ts +32 -29
- package/src/components/content-unavailable-view/content-unavailable-view.tsx +64 -48
- package/src/components/content-view/content-view.tsx +168 -159
- package/src/components/content-view/index.ts +1 -1
- package/src/components/context-menu/conceal-menu-source.ts +25 -25
- package/src/components/context-menu/context-menu-host.tsx +439 -398
- package/src/components/context-menu/context-menu-store.ts +125 -123
- package/src/components/context-menu/menu-navigation.ts +25 -18
- package/src/components/context-menu/menu-position.ts +33 -29
- package/src/components/context-menu/menu-reveal.ts +32 -32
- package/src/components/context-menu/use-context-menu.ts +63 -56
- package/src/components/conversation/conversation.tsx +265 -263
- package/src/components/conversation/index.ts +1 -1
- package/src/components/date-picker/date-picker.tsx +95 -94
- package/src/components/date-picker/date-value.ts +20 -10
- package/src/components/dialog/dialog-host.tsx +105 -103
- package/src/components/dialog/dialog-store.ts +37 -36
- package/src/components/dialog/dialog.tsx +192 -179
- package/src/components/dialog/index.ts +1 -1
- package/src/components/disclosure-group/disclosure-group.tsx +93 -86
- package/src/components/divider/divider.tsx +24 -22
- package/src/components/inline-disclosure/inline-disclosure.tsx +40 -36
- package/src/components/keyboard-shortcut/keyboard-shortcut.tsx +23 -19
- package/src/components/labeled-content/labeled-content.tsx +68 -68
- package/src/components/locale-switcher/index.ts +1 -1
- package/src/components/locale-switcher/locale-switcher.tsx +279 -251
- package/src/components/menu/menu.tsx +75 -58
- package/src/components/morph/index.ts +2 -2
- package/src/components/morph/morph.tsx +227 -201
- package/src/components/morph/use-morph-disclosure.ts +19 -19
- package/src/components/one-time-code/one-time-code.tsx +216 -200
- package/src/components/picker/picker-trigger.ts +16 -13
- package/src/components/picker/picker.tsx +371 -345
- package/src/components/popover/anchored-surface.tsx +253 -229
- package/src/components/popover/index.ts +50 -0
- package/src/components/popover/popover-content.tsx +334 -0
- package/src/components/popover/popover-fit.ts +58 -53
- package/src/components/popover/popover-root.tsx +97 -0
- package/src/components/popover/popover-trigger.tsx +71 -0
- package/src/components/profile-image/profile-image.tsx +80 -64
- package/src/components/progress-view/progress-view.tsx +61 -59
- package/src/components/progress-view/use-liquid-progress.ts +38 -38
- package/src/components/radio-group/radio-group.tsx +71 -68
- package/src/components/search-field/expanding-search-field.tsx +191 -177
- package/src/components/search-field/search-field.tsx +59 -50
- package/src/components/search-list/search-list.tsx +246 -236
- package/src/components/section/section.tsx +58 -58
- package/src/components/secure-field/secure-field.tsx +3 -3
- package/src/components/segmented-control/segmented-control.tsx +136 -136
- package/src/components/sheet/modal-environment.ts +71 -64
- package/src/components/sheet/sheet-portal.tsx +58 -53
- package/src/components/sheet/sheet.tsx +146 -141
- package/src/components/sheet/use-sheet-focus.ts +97 -82
- package/src/components/sidebar/sidebar.tsx +78 -78
- package/src/components/skeleton/skeleton.tsx +30 -21
- package/src/components/slider/slider.tsx +113 -104
- package/src/components/slosh-slider/liquid-step.ts +32 -31
- package/src/components/slosh-slider/slosh-slider.tsx +265 -228
- package/src/components/stat-tile/index.ts +1 -1
- package/src/components/stat-tile/stat-tile.tsx +79 -68
- package/src/components/status-indicator/status-indicator.tsx +40 -37
- package/src/components/stepper/rolling-digit.tsx +82 -68
- package/src/components/stepper/stepper.tsx +122 -113
- package/src/components/swatch-picker/swatch-picker.tsx +120 -120
- package/src/components/tab-bar/tab-bar.tsx +149 -148
- package/src/components/tab-view/tab-view.tsx +140 -137
- package/src/components/table/table.tsx +117 -98
- package/src/components/text-editor/text-editor.tsx +34 -29
- package/src/components/text-field/text-field.tsx +182 -180
- package/src/components/toast/toast-store.ts +127 -115
- package/src/components/toast/toaster.tsx +361 -347
- package/src/components/toggle/toggle.tsx +297 -282
- package/src/components/tooltip/tooltip-host.tsx +157 -150
- package/src/components/view-controller/index.ts +1 -1
- package/src/components/view-controller/view-controller.tsx +64 -53
- package/src/components/wake-slider/wake-slider.tsx +220 -205
- package/src/hooks/scroll/minimize-decision.ts +11 -7
- package/src/hooks/use-anchored-disclosure.ts +19 -19
- package/src/hooks/use-anchored-placement.ts +29 -25
- package/src/hooks/use-dismiss.ts +33 -29
- package/src/hooks/use-floating-dismiss.ts +24 -22
- package/src/hooks/use-media-query.ts +67 -60
- package/src/hooks/use-minimize-on-scroll.ts +69 -60
- package/src/hooks/use-visual-viewport.ts +63 -63
- package/src/hooks/viewport/types.ts +16 -16
- package/src/hooks/viewport/viewport-metrics.ts +16 -10
- package/src/icons/icons.tsx +440 -328
- package/src/index.ts +91 -91
- package/src/lib/anchored-placement.ts +70 -65
- package/src/lib/class-names.ts +14 -13
- package/src/lib/clipboard.ts +8 -7
- package/src/lib/date.ts +61 -60
- package/src/lib/floating-layers.ts +39 -24
- package/src/lib/haptics.ts +10 -10
- package/src/lib/language.ts +9 -9
- package/src/lib/range-value.ts +27 -21
- package/src/lib/screen-edges.ts +33 -30
- package/src/lib/shapes.ts +38 -34
- package/src/machines/popover.machine.ts +51 -0
- package/src/motion/transitions.ts +46 -43
- package/src/styles/code-block.css +69 -43
- package/src/styles/motion-controls.css +393 -191
- package/src/tokens.ts +1 -1
- package/dist/types/src/components/popover/popover.d.ts +0 -21
- package/src/components/popover/popover.tsx +0 -322
package/src/lib/haptics.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/** The feedback kinds the systems share, from a selection tick to an error. */
|
|
2
2
|
export type HapticKind =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
| "selection"
|
|
4
|
+
| "light"
|
|
5
|
+
| "medium"
|
|
6
|
+
| "heavy"
|
|
7
|
+
| "success"
|
|
8
|
+
| "warning"
|
|
9
|
+
| "error";
|
|
10
10
|
|
|
11
|
-
let player: (kind: HapticKind) => void = () => {}
|
|
11
|
+
let player: (kind: HapticKind) => void = () => {};
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Components only ask for feedback; the app decides how it plays on this
|
|
15
15
|
* device (system haptics, a vibration, or nothing) and whether it's on.
|
|
16
16
|
*/
|
|
17
17
|
export function setHapticPlayer(next: (kind: HapticKind) => void): void {
|
|
18
|
-
|
|
18
|
+
player = next;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function haptic(kind: HapticKind): void {
|
|
22
|
-
|
|
22
|
+
player(kind);
|
|
23
23
|
}
|
package/src/lib/language.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/** A language's name in itself, capitalized: "Français", "中文". */
|
|
2
2
|
export function getNativeLanguageName(tag: string) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const name = new Intl.DisplayNames([tag], {
|
|
4
|
+
type: "language",
|
|
5
|
+
}).of(tag);
|
|
6
|
+
return name ? name.charAt(0).toUpperCase() + name.slice(1) : tag;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/** A language's name as read in `displayLocale`: "French" in English. */
|
|
10
10
|
export function getLocalizedLanguageName(tag: string, displayLocale: string) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
return (
|
|
12
|
+
new Intl.DisplayNames([displayLocale], {
|
|
13
|
+
type: "language",
|
|
14
|
+
}).of(tag) ?? tag
|
|
15
|
+
);
|
|
16
16
|
}
|
package/src/lib/range-value.ts
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
/** Keep controlled numeric inputs within finite bounds without floating-point drift. */
|
|
2
2
|
export function clampRange(value: number, min: number, max: number): number {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
if (!Number.isFinite(value)) return min;
|
|
4
|
+
return Math.min(max, Math.max(min, value));
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
/** The nearest reachable step from min, optionally allowing an exact maximum. */
|
|
8
8
|
export function stepRange(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
value: number,
|
|
10
|
+
direction: -1 | 1,
|
|
11
|
+
min: number,
|
|
12
|
+
max: number,
|
|
13
|
+
step: number,
|
|
14
14
|
): number {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
const precision = Math.min(
|
|
16
|
+
12,
|
|
17
|
+
Math.max(0, ...[min, max, step].map(decimalPlaces)),
|
|
18
|
+
);
|
|
19
|
+
const factor = 10 ** precision;
|
|
20
|
+
const low = Math.round(min * factor);
|
|
21
|
+
const high = Math.round(max * factor);
|
|
22
|
+
const increment = Math.max(1, Math.round(step * factor));
|
|
23
|
+
const current = Math.round(clampRange(value, min, max) * factor);
|
|
24
|
+
const next =
|
|
25
|
+
direction > 0
|
|
26
|
+
? low + (Math.floor((current - low) / increment) + 1) * increment
|
|
27
|
+
: low + (Math.ceil((current - low) / increment) - 1) * increment;
|
|
28
|
+
return clampRange(Math.min(high, Math.max(low, next)) / factor, min, max);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function decimalPlaces(value: number): number {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
const text = String(value);
|
|
33
|
+
const [mantissa, exponent] = text.toLowerCase().split("e");
|
|
34
|
+
return Math.max(
|
|
35
|
+
0,
|
|
36
|
+
(mantissa?.split(".")[1]?.length ?? 0) - Number(exponent ?? 0),
|
|
37
|
+
);
|
|
32
38
|
}
|
package/src/lib/screen-edges.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export interface ScreenEdges {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
top: number;
|
|
3
|
+
right: number;
|
|
4
|
+
bottom: number;
|
|
5
|
+
left: number;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
let probe: HTMLDivElement | undefined
|
|
8
|
+
let probe: HTMLDivElement | undefined;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* How far menus and popovers keep from each side of the screen: clear of
|
|
@@ -13,29 +13,32 @@ let probe: HTMLDivElement | undefined
|
|
|
13
13
|
* further from the glass, as the systems' own menus are.
|
|
14
14
|
*/
|
|
15
15
|
export function screenEdges(): ScreenEdges {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
16
|
+
const margin =
|
|
17
|
+
typeof window !== "undefined" &&
|
|
18
|
+
window.matchMedia("(pointer: coarse)").matches
|
|
19
|
+
? 12
|
|
20
|
+
: 8;
|
|
21
|
+
if (typeof document === "undefined") {
|
|
22
|
+
return {
|
|
23
|
+
top: margin,
|
|
24
|
+
right: margin,
|
|
25
|
+
bottom: margin,
|
|
26
|
+
left: margin,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (!probe) {
|
|
30
|
+
probe = document.createElement("div");
|
|
31
|
+
probe.setAttribute("aria-hidden", "true");
|
|
32
|
+
probe.style.cssText =
|
|
33
|
+
"position:fixed;inset:0;visibility:hidden;pointer-events:none;" +
|
|
34
|
+
"padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)";
|
|
35
|
+
}
|
|
36
|
+
if (!probe.isConnected) document.body.appendChild(probe);
|
|
37
|
+
const style = getComputedStyle(probe);
|
|
38
|
+
return {
|
|
39
|
+
top: Number.parseFloat(style.paddingTop) + margin,
|
|
40
|
+
right: Number.parseFloat(style.paddingRight) + margin,
|
|
41
|
+
bottom: Number.parseFloat(style.paddingBottom) + margin,
|
|
42
|
+
left: Number.parseFloat(style.paddingLeft) + margin,
|
|
43
|
+
};
|
|
41
44
|
}
|
package/src/lib/shapes.ts
CHANGED
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
/** Material 3 expressive outlines: a circle and the scalloped "cookie", "clover", and "sunny" shapes. */
|
|
2
2
|
export const shapes = [
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
] as const
|
|
3
|
+
"circle",
|
|
4
|
+
"cookie4",
|
|
5
|
+
"cookie6",
|
|
6
|
+
"cookie9",
|
|
7
|
+
"clover",
|
|
8
|
+
"sunny",
|
|
9
|
+
/** Reserved for the Pherus mark itself, so it never matches a project's icon. */
|
|
10
|
+
"cookie12",
|
|
11
|
+
] as const;
|
|
12
12
|
|
|
13
|
-
export type Shape = (typeof shapes)[number]
|
|
13
|
+
export type Shape = (typeof shapes)[number];
|
|
14
14
|
|
|
15
15
|
/** Lobe count and wave depth (as a fraction of the radius) for each wavy shape. */
|
|
16
|
-
const waves: Record<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
16
|
+
const waves: Record<
|
|
17
|
+
Exclude<Shape, "circle">,
|
|
18
|
+
{ lobes: number; depth: number }
|
|
19
|
+
> = {
|
|
20
|
+
cookie4: { lobes: 4, depth: 0.08 },
|
|
21
|
+
cookie6: { lobes: 6, depth: 0.07 },
|
|
22
|
+
cookie9: { lobes: 9, depth: 0.055 },
|
|
23
|
+
clover: { lobes: 4, depth: 0.16 },
|
|
24
|
+
sunny: { lobes: 8, depth: 0.045 },
|
|
25
|
+
cookie12: { lobes: 12, depth: 0.04 },
|
|
26
|
+
};
|
|
24
27
|
|
|
25
|
-
const STEPS = 144
|
|
28
|
+
const STEPS = 144;
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* An SVG path for a Material 3 expressive shape centred on (cx, cy): a circle
|
|
@@ -31,25 +34,26 @@ const STEPS = 144
|
|
|
31
34
|
* the same `r`, keeping icons optically the same size.
|
|
32
35
|
*/
|
|
33
36
|
export function shapePath(shape: Shape, cx: number, cy: number, r: number) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
if (shape === "circle") {
|
|
38
|
+
return `M ${cx - r} ${cy} a ${r} ${r} 0 1 0 ${r * 2} 0 a ${r} ${r} 0 1 0 ${-r * 2} 0 Z`;
|
|
39
|
+
}
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
const { lobes, depth } = waves[shape];
|
|
42
|
+
const base = r / (1 + depth);
|
|
43
|
+
const points: string[] = [];
|
|
44
|
+
for (let i = 0; i < STEPS; i++) {
|
|
45
|
+
const theta = (i / STEPS) * Math.PI * 2 - Math.PI / 2;
|
|
46
|
+
const radius = base * (1 + depth * Math.cos(lobes * (theta + Math.PI / 2)));
|
|
47
|
+
const x = cx + radius * Math.cos(theta);
|
|
48
|
+
const y = cy + radius * Math.sin(theta);
|
|
49
|
+
points.push(`${i === 0 ? "M" : "L"} ${x.toFixed(2)} ${y.toFixed(2)}`);
|
|
50
|
+
}
|
|
51
|
+
return `${points.join(" ")} Z`;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
/**
|
|
52
55
|
* The app wide `dualTone` rule dims every svg path for two tone icons; a
|
|
53
56
|
* drawn shape or illustration opts out with this so its colors stay true.
|
|
54
57
|
*/
|
|
55
|
-
export const plainSvg =
|
|
58
|
+
export const plainSvg =
|
|
59
|
+
"cursor-[inherit] [&_path]:opacity-100 [&_path]:transform-none";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Popover state machine — pure function, no React, no DOM.
|
|
3
|
+
*
|
|
4
|
+
* Translates directly to a Rust enum with match arms.
|
|
5
|
+
*
|
|
6
|
+
* States:
|
|
7
|
+
* closed → nothing visible
|
|
8
|
+
* opening → surface morphing from trigger to content
|
|
9
|
+
* open → content fully visible
|
|
10
|
+
* closing → surface morphing back to trigger
|
|
11
|
+
*
|
|
12
|
+
* The OPENED/CLOSED events are fired by onAnimationComplete,
|
|
13
|
+
* so the machine stays in "opening"/"closing" until the animation
|
|
14
|
+
* actually finishes — enabling interruptibility (close during open).
|
|
15
|
+
*/
|
|
16
|
+
export type PopoverState = "closed" | "opening" | "open" | "closing";
|
|
17
|
+
|
|
18
|
+
export type PopoverEvent = "OPEN" | "OPENED" | "CLOSE" | "CLOSED" | "TOGGLE";
|
|
19
|
+
|
|
20
|
+
export function popoverMachine(
|
|
21
|
+
state: PopoverState,
|
|
22
|
+
event: PopoverEvent,
|
|
23
|
+
): PopoverState {
|
|
24
|
+
switch (state) {
|
|
25
|
+
case "closed":
|
|
26
|
+
return event === "OPEN" || event === "TOGGLE" ? "opening" : "closed";
|
|
27
|
+
case "opening":
|
|
28
|
+
if (event === "CLOSE" || event === "TOGGLE") return "closing";
|
|
29
|
+
if (event === "OPENED") return "open";
|
|
30
|
+
return "opening";
|
|
31
|
+
case "open":
|
|
32
|
+
return event === "CLOSE" || event === "TOGGLE" ? "closing" : "open";
|
|
33
|
+
case "closing":
|
|
34
|
+
if (event === "OPEN" || event === "TOGGLE") return "opening";
|
|
35
|
+
if (event === "CLOSED") return "closed";
|
|
36
|
+
return "closing";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type PopoverContextValue = {
|
|
41
|
+
state: PopoverState;
|
|
42
|
+
send: (event: PopoverEvent) => void;
|
|
43
|
+
/** The trigger element — set by PopoverTrigger, read by PopoverContent for positioning. */
|
|
44
|
+
triggerRef: React.RefObject<HTMLElement | null>;
|
|
45
|
+
/** Unique ID for aria-controls + layoutId morphing. */
|
|
46
|
+
contentId: string;
|
|
47
|
+
/** Shared layoutId for motion's matched-geometry transition. */
|
|
48
|
+
surfaceId: string;
|
|
49
|
+
/** Whether the popover is open or transitioning (not closed). */
|
|
50
|
+
isPresent: boolean;
|
|
51
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { springs } from "@passui/tokens/motion"
|
|
2
|
-
import type { Transition } from "motion/react"
|
|
1
|
+
import { springs } from "@passui/tokens/motion";
|
|
2
|
+
import type { Transition } from "motion/react";
|
|
3
3
|
|
|
4
4
|
/** Design-token springs as motion/react transitions. */
|
|
5
5
|
export const spring = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} as const satisfies Record<keyof typeof springs, Transition
|
|
6
|
+
smooth: { type: "spring", ...springs.smooth },
|
|
7
|
+
snappy: { type: "spring", ...springs.snappy },
|
|
8
|
+
bouncy: { type: "spring", ...springs.bouncy },
|
|
9
|
+
} as const satisfies Record<keyof typeof springs, Transition>;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Apple's fluid overshoot: cubic-bezier(0.34, 1.56, 0.1, 1).
|
|
@@ -16,9 +16,9 @@ export const spring = {
|
|
|
16
16
|
* from the trigger and snaps into place with a physical bounce.
|
|
17
17
|
*/
|
|
18
18
|
export const fluidOvershoot = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} as const
|
|
19
|
+
duration: 0.4,
|
|
20
|
+
ease: [0.34, 1.56, 0.1, 1] as [number, number, number, number],
|
|
21
|
+
} as const;
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Exit motion: content collapses back toward its source.
|
|
@@ -26,11 +26,11 @@ export const fluidOvershoot = {
|
|
|
26
26
|
* like a water drop absorbing back into its origin.
|
|
27
27
|
*/
|
|
28
28
|
export const fluidCollapse = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} as const
|
|
29
|
+
duration: 0.28,
|
|
30
|
+
ease: [0.4, 0, 0.6, 1] as [number, number, number, number],
|
|
31
|
+
} as const;
|
|
32
32
|
|
|
33
|
-
export type FloatingPanelSide = "above" | "below"
|
|
33
|
+
export type FloatingPanelSide = "above" | "below";
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Anchored panels settle toward their source without shrinking their text.
|
|
@@ -39,20 +39,23 @@ export type FloatingPanelSide = "above" | "below"
|
|
|
39
39
|
* crossfade, rather than a plain slide.
|
|
40
40
|
*/
|
|
41
41
|
export function floatingPanelMotion(side: FloatingPanelSide = "below") {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
const direction = side === "above" ? 1 : -1;
|
|
43
|
+
return {
|
|
44
|
+
initial: { opacity: 0, scale: 0.92, y: direction * 6 },
|
|
45
|
+
animate: { opacity: 1, scale: 1, y: 0 },
|
|
46
|
+
exit: { opacity: 0, scale: 0.95, y: direction * 4 },
|
|
47
|
+
transition: {
|
|
48
|
+
...fluidOvershoot,
|
|
49
|
+
opacity: {
|
|
50
|
+
duration: 0.16,
|
|
51
|
+
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
} as const;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/** Default below-anchor presentation, retained for existing consumers. */
|
|
55
|
-
export const popoverMotion = floatingPanelMotion()
|
|
58
|
+
export const popoverMotion = floatingPanelMotion();
|
|
56
59
|
|
|
57
60
|
/**
|
|
58
61
|
* Zoom/matched-geometry transition for dialogs and center-placed sheets.
|
|
@@ -62,11 +65,11 @@ export const popoverMotion = floatingPanelMotion()
|
|
|
62
65
|
* asynchronously — not a harsh switch.
|
|
63
66
|
*/
|
|
64
67
|
export const zoomReveal = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} as const
|
|
68
|
+
initial: { opacity: 0, scale: 0.88 },
|
|
69
|
+
animate: { opacity: 1, scale: 1 },
|
|
70
|
+
exit: { opacity: 0, scale: 0.92 },
|
|
71
|
+
transition: fluidOvershoot,
|
|
72
|
+
} as const;
|
|
70
73
|
|
|
71
74
|
/**
|
|
72
75
|
* Content crossfade for elements inside an overlay.
|
|
@@ -75,20 +78,20 @@ export const zoomReveal = {
|
|
|
75
78
|
* and popovers — the container arrives first, then content fades in.
|
|
76
79
|
*/
|
|
77
80
|
export const contentCrossfade = {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} as const
|
|
81
|
+
initial: { opacity: 0, scale: 0.96 },
|
|
82
|
+
animate: { opacity: 1, scale: 1 },
|
|
83
|
+
exit: { opacity: 0, scale: 0.98 },
|
|
84
|
+
transition: {
|
|
85
|
+
duration: 0.24,
|
|
86
|
+
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
|
|
87
|
+
delay: 0.04,
|
|
88
|
+
},
|
|
89
|
+
} as const;
|
|
87
90
|
|
|
88
91
|
/** Floating bars that rise from the bottom edge. */
|
|
89
92
|
export const riseMotion = {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
} as const
|
|
93
|
+
initial: { opacity: 0, y: 32 },
|
|
94
|
+
animate: { opacity: 1, y: 0 },
|
|
95
|
+
exit: { opacity: 0, y: 24 },
|
|
96
|
+
transition: spring.smooth,
|
|
97
|
+
} as const;
|
|
@@ -1,45 +1,71 @@
|
|
|
1
1
|
@layer components {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
2
|
+
.passui-code-block pre {
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding-block: 1rem;
|
|
5
|
+
padding-inline-end: 1.5rem;
|
|
6
|
+
overflow-x: auto;
|
|
7
|
+
font-family: var(--font-mono);
|
|
8
|
+
font-size: var(--text-footnote);
|
|
9
|
+
line-height: 1.75;
|
|
10
|
+
color: var(--color-label);
|
|
11
|
+
/* biome-ignore lint/complexity/noImportantStyles: CSS utility override */
|
|
12
|
+
background: transparent !important;
|
|
13
|
+
counter-reset: code-line;
|
|
14
|
+
tab-size: 4;
|
|
15
|
+
}
|
|
16
|
+
.passui-code-block .line {
|
|
17
|
+
display: inline-block;
|
|
18
|
+
min-width: 100%;
|
|
19
|
+
}
|
|
20
|
+
.passui-code-block[data-line-numbers] .line::before {
|
|
21
|
+
counter-increment: code-line;
|
|
22
|
+
content: counter(code-line);
|
|
23
|
+
display: inline-block;
|
|
24
|
+
width: 3rem;
|
|
25
|
+
margin-inline-end: 1.25rem;
|
|
26
|
+
color: var(--color-label-tertiary);
|
|
27
|
+
text-align: end;
|
|
28
|
+
user-select: none;
|
|
29
|
+
}
|
|
30
|
+
.passui-code-block:not([data-line-numbers]) pre {
|
|
31
|
+
padding-inline-start: 1rem;
|
|
32
|
+
}
|
|
33
|
+
.passui-code-block[data-size="sm"] pre {
|
|
34
|
+
padding-block: 0.75rem;
|
|
35
|
+
font-size: var(--text-caption);
|
|
36
|
+
line-height: 1.6;
|
|
37
|
+
}
|
|
38
|
+
.passui-code-block[data-size="sm"][data-line-numbers] .line::before {
|
|
39
|
+
width: 2.5rem;
|
|
40
|
+
margin-inline-end: 1rem;
|
|
41
|
+
}
|
|
42
|
+
.passui-code-block[data-size="lg"] pre {
|
|
43
|
+
padding-block: 1.25rem;
|
|
44
|
+
font-size: var(--text-subheadline);
|
|
45
|
+
line-height: 1.8;
|
|
46
|
+
}
|
|
47
|
+
.passui-code-block[data-size="lg"][data-line-numbers] .line::before {
|
|
48
|
+
width: 3.5rem;
|
|
49
|
+
margin-inline-end: 1.5rem;
|
|
50
|
+
}
|
|
51
|
+
.passui-code-block .shiki,
|
|
52
|
+
.passui-code-block .shiki span {
|
|
53
|
+
color: var(--shiki-light);
|
|
54
|
+
/* biome-ignore lint/complexity/noImportantStyles: CSS utility override */
|
|
55
|
+
background: transparent !important;
|
|
56
|
+
}
|
|
57
|
+
@media (prefers-color-scheme: dark) {
|
|
58
|
+
.passui-code-block .shiki,
|
|
59
|
+
.passui-code-block .shiki span {
|
|
60
|
+
color: var(--shiki-dark);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
[data-theme="light"] .passui-code-block .shiki,
|
|
64
|
+
[data-theme="light"] .passui-code-block .shiki span {
|
|
65
|
+
color: var(--shiki-light);
|
|
66
|
+
}
|
|
67
|
+
[data-theme="dark"] .passui-code-block .shiki,
|
|
68
|
+
[data-theme="dark"] .passui-code-block .shiki span {
|
|
69
|
+
color: var(--shiki-dark);
|
|
70
|
+
}
|
|
45
71
|
}
|