beez-ui 2.6.2 → 2.7.1
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/CHANGELOG.md +29 -0
- package/README.md +47 -27
- package/dist/components/alert-dialog.d.ts +2 -2
- package/dist/components/alert-dialog.js +3 -3
- package/dist/components/dialog-surface.js +1 -1
- package/dist/components/dialog.d.ts +5 -4
- package/dist/components/dialog.js +7 -6
- package/dist/components/rich-link-editor.js +1 -1
- package/dist/components/sidebar.js +4 -9
- package/dist/motion/arc-tokens.d.ts +5 -1
- package/dist/motion/arc-tokens.js +19 -3
- package/dist/motion/glide-indicator.d.ts +4 -6
- package/dist/motion/glide-indicator.js +61 -23
- package/dist/motion/motion-slot.js +30 -61
- package/dist/motion/surface-keyframes.d.ts +12 -1
- package/dist/motion/surface-keyframes.js +48 -83
- package/dist/motion/tokens.d.ts +97 -61
- package/dist/motion/tokens.js +95 -99
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ Todos los cambios relevantes de beez-ui se documentan en este archivo con el for
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.7.1] - 2026-10-16
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `RichLinkEditor` ya no pinta su propio fondo: deja ver la superficie que lo contiene, así dentro de un diálogo o de una tarjeta en modo oscuro deja de verse como un bloque de otro color.
|
|
12
|
+
|
|
13
|
+
## [2.7.0] - 2026-10-16
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `beez-ui/motion-tokens` suma los presets de Arc que faltaban: `MOTION_TIMING.instant`, `MOTION_TIMING.standard`, `MOTION_TIMING.considered`, `MOTION_EASE_EXIT`, `MOTION_EASE_STANDARD`, `MOTION_EXIT_SCALE`, `MOTION_TOOLTIP_SCALE` y `MOTION_DIALOG_EXIT_DISTANCE`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Los tokens de `beez-ui/motion-tokens` toman los valores de los presets de Arc y conservan sus nombres: los springs pasan a `snappy`, `smooth` o `morph` (expresados con `visualDuration` y `bounce` en lugar de `stiffness`, `damping` y `mass`), las duraciones y curvas usan las de Arc y la presión baja a 0.97.
|
|
22
|
+
- `Dialog` y `AlertDialog` entran como el diálogo de Arc: el panel sube 8 px y crece desde 0.96 con un resorte suave mientras aparece, y sale rápido (0.16 s), en lugar de desplegarse desde el centro. La transformación y la opacidad que el panel recibe por `className` o `style` se mantienen durante toda la animación, y reabrirlo mientras sale lo devuelve desde donde está.
|
|
23
|
+
- `Input`, `Textarea`, `InputGroup` y `SelectTrigger` ya no tiemblan al pasar a `aria-invalid="true"`: el error se indica con el color y el mensaje, sin mover el campo.
|
|
24
|
+
- Las opciones de `Select`, `Alert`, `FormMessage` y el ícono de `AnimatedThemeToggler` aparecen con un fundido y una escala breves, sin desenfoque; las opciones del `Select` entran todas juntas, sin escalonarse.
|
|
25
|
+
- El ancho del `Sidebar` cambia con el resorte `smooth` de Arc (0.4 s, sin rebote), más suave que antes.
|
|
26
|
+
|
|
27
|
+
### Deprecated
|
|
28
|
+
|
|
29
|
+
- `MOTION_TIMING.centerMorph`, `MOTION_TIMING.centerMorphFold`, `MOTION_EASE_UNFOLD` y `MOTION_CENTER_MORPH_FOLDED_PERCENT`: los diálogos ya no se despliegan desde el centro. Siguen exportados con su valor.
|
|
30
|
+
- `MOTION_TIMING.shake` y `MOTION_INVALID_SHAKE_PX`: los campos inválidos ya no tiemblan. Siguen exportados con su valor.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Al moverse con el teclado mientras un `Select` o un `DropdownMenu` todavía se está abriendo, el resaltado se desliza hasta el tamaño y la posición finales de la opción y ya no salta al terminar.
|
|
35
|
+
|
|
7
36
|
## [2.6.2] - 2026-10-16
|
|
8
37
|
|
|
9
38
|
### Fixed
|
package/README.md
CHANGED
|
@@ -71,47 +71,67 @@ Los `Sheet` superiores e inferiores limitan su altura al viewport dinámico (`10
|
|
|
71
71
|
|
|
72
72
|
## Movimiento
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
74
|
+
El movimiento sigue a [Arc](https://uiarc.dev): explica causa y efecto (qué se abrió,
|
|
75
|
+
qué cambió, de dónde vino) y no decora. Si una animación no explica nada, no está.
|
|
76
|
+
Las animaciones usan la dependencia `motion`: `animate` controla la reproducción,
|
|
77
|
+
`hover` y `press` los gestos, y `AnimatePresence` / `usePresence` retienen los
|
|
78
|
+
overlays durante su salida. Los presets y tiempos viven en `src/motion/`. No se usan
|
|
79
|
+
keyframes CSS para estas animaciones.
|
|
78
80
|
|
|
79
81
|
`MotionSlot` anima el nodo original del primitive mediante refs compuestos,
|
|
80
|
-
sin agregar wrappers al DOM ni reemplazar sus handlers.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
sin agregar wrappers al DOM ni reemplazar sus handlers. Los tokens exportados en
|
|
83
|
+
`beez-ui/motion-tokens` toman los valores de los presets de Arc
|
|
84
|
+
(`components/arc/lib/motion-tokens.ts`):
|
|
85
|
+
|
|
86
|
+
- Springs: `snappy` (0.26 s, rebote 0.12) para presiones, indicadores chicos y cambios de
|
|
87
|
+
ícono (`SPRING_PRESS`, `SPRING_POP`, `SPRING_CHEVRON`, `SPRING_HIGHLIGHT`, `SPRING_TOOLTIP`);
|
|
88
|
+
`smooth` (0.4 s, sin rebote) para paneles y todo lo que informa un estado
|
|
89
|
+
(`SPRING_PANEL`, `SPRING_THUMB`); `morph` (0.42 s, rebote 0.16) para resaltados compartidos
|
|
90
|
+
(`SPRING_LAYOUT`, `SPRING_TABS`).
|
|
91
|
+
- Duraciones: `instant` 0.12 s, `fast` 0.16 s, `exit` 0.18 s, `enter`/`standard` 0.24 s y
|
|
92
|
+
`considered` 0.48 s. Las salidas son más cortas que las entradas.
|
|
93
|
+
- Curvas: `MOTION_EASE` (entrada), `MOTION_EASE_EXIT`, `MOTION_EASE_STANDARD` y
|
|
94
|
+
`MOTION_EASE_IN_OUT`.
|
|
95
|
+
|
|
96
|
+
Los nombres de los tokens se mantienen entre versiones; los del despliegue desde el centro
|
|
97
|
+
y del temblor de campos inválidos quedan deprecados y conservan su valor.
|
|
98
|
+
|
|
99
|
+
- `Button` usa la presión de Arc: se comprime a 0.97 con el spring `snappy` (un poco más en
|
|
84
100
|
botones de solo ícono y menos en los anchos), sin escalar los disparadores de menús; su
|
|
85
101
|
texto cambia de ancho con un spring. Los ítems de `Sidebar` y `Tabs` se comprimen a 0.98.
|
|
86
102
|
- `Checkbox` y `RadioGroup` se comprimen a 0.92. La marca del checkbox aparece
|
|
87
|
-
con pop y trazo (`pathLength`)
|
|
88
|
-
- El thumb de `Switch` viaja con
|
|
89
|
-
- `Input`, `Textarea`, `InputGroup` y `SelectTrigger`
|
|
90
|
-
`aria-invalid="true"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
con pop y trazo (`pathLength`); el punto del radio aparece con spring.
|
|
104
|
+
- El thumb de `Switch` viaja con el spring `smooth`, sin rebote, y se aplasta mientras se presiona.
|
|
105
|
+
- `Input`, `Textarea`, `InputGroup` y `SelectTrigger` no se mueven al pasar a
|
|
106
|
+
`aria-invalid="true"`: el error se indica con el color y el mensaje. `FormMessage` y
|
|
107
|
+
`Alert` aparecen con un fundido y una escala breves (desde 0.98), sin desenfoque.
|
|
108
|
+
- `Tooltip` sube 3 px desde 0.97 mientras aparece y sale en el lugar, sin desenfoque.
|
|
109
|
+
`Popover` y `HoverCard` se acercan desde su trigger con escala y fundido; `DropdownMenu`
|
|
110
|
+
y `Select` escalan desde 0.96 y se revelan con un clip desde la esquina más cercana al trigger.
|
|
111
|
+
- `Dialog` y `AlertDialog` entran como el diálogo de Arc: el fondo se oscurece en 0.24 s y el
|
|
112
|
+
panel sube 8 px y crece desde 0.96 con el spring `smooth` mientras aparece en 0.16 s; al
|
|
113
|
+
cerrar baja 4 px hasta 0.98 y se desvanece en 0.16 s, y una reapertura parte de donde
|
|
114
|
+
está. `Sheet` entra desde su borde con spring y sale con la curva de cajón (0.24 s), sin
|
|
115
|
+
demorar la siguiente interacción.
|
|
96
116
|
- `GlideSlot` desliza el indicador activo entre ítems como un `layoutId` compartido:
|
|
97
117
|
la pestaña activa de `Tabs` (fondo o subrayado), la
|
|
98
118
|
página actual de `PaginationContent`, y al navegar con teclado el ítem resaltado de
|
|
99
119
|
`DropdownMenu` y `Select` y la sugerencia activa de `FilterQueryBar`. Con el puntero,
|
|
100
120
|
esos resaltados lo siguen al instante: el propio puntero ya marca la posición.
|
|
101
|
-
- Las superficies
|
|
121
|
+
- Las superficies que se revelan con clip dejan 24 px libres fuera de la
|
|
102
122
|
caja, así su borde (`ring`) y su sombra se ven desde el primer frame. Una copia
|
|
103
123
|
transitoria viaja entre ítems y se elimina al llegar, devolviendo el estilo al ítem.
|
|
104
124
|
- El chevron de `SelectTrigger` gira 180° al abrir y los chevrons de `DataTable`
|
|
105
125
|
(grupos y columnas) giran en lugar de cambiar de ícono; CSS define el ángulo final.
|
|
106
|
-
- Las opciones del `Select` entran
|
|
107
|
-
|
|
108
|
-
- `Sidebar`
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- El ícono de `AnimatedThemeToggler`
|
|
113
|
-
`Dialog` aparece con un pop demorado.
|
|
114
|
-
- El contenido de `Tabs` entra con un desplazamiento de 4 px
|
|
126
|
+
- Las opciones del `Select` entran todas juntas con un fundido y una escala breves, sin
|
|
127
|
+
escalonarse ni desenfocarse, y los checks de ítems de `Select` y `DropdownMenu` aparecen con pop.
|
|
128
|
+
- El ancho de `Sidebar` cambia con el spring `smooth` entre el panel y el riel de íconos, las
|
|
129
|
+
etiquetas se desvanecen al colapsar, una píldora compartida sigue al ítem activo y al
|
|
130
|
+
hovereado, los submenús se despliegan escalonados y en pantallas chicas se abre como hoja
|
|
131
|
+
con foco atrapado.
|
|
132
|
+
- El ícono de `AnimatedThemeToggler` crece desde 0.6 con el spring `snappy` mientras aparece,
|
|
133
|
+
sin desenfoque; el botón de cierre de `Dialog` aparece con un pop demorado.
|
|
134
|
+
- El contenido de `Tabs` entra con un desplazamiento de 4 px.
|
|
115
135
|
Cards y enlaces responden al hover; el avatar bajo el puntero de un `AvatarGroup` se
|
|
116
136
|
eleva. Un brillo recorre el `Skeleton` desde su `::after` con reproducción nativa,
|
|
117
137
|
sin trabajo por frame en JavaScript.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Confirmation dialog on Arc's Dialog surface (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): the same
|
|
3
|
-
* overlay, raised panel, title and description type as `Dialog`, so both read as one family. It
|
|
4
|
-
*
|
|
3
|
+
* overlay, raised panel, title and description type and dialog transition as `Dialog`, so both read as one family. It
|
|
4
|
+
* keeps beez-ui's media slot and Arc `Button` actions.
|
|
5
5
|
*/
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { c as _c } from "react/compiler-runtime";
|
|
3
3
|
/**
|
|
4
4
|
* Confirmation dialog on Arc's Dialog surface (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): the same
|
|
5
|
-
* overlay, raised panel, title and description type as `Dialog`, so both read as one family. It
|
|
6
|
-
*
|
|
5
|
+
* overlay, raised panel, title and description type and dialog transition as `Dialog`, so both read as one family. It
|
|
6
|
+
* keeps beez-ui's media slot and Arc `Button` actions.
|
|
7
7
|
*/
|
|
8
8
|
import * as React from "react";
|
|
9
9
|
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
|
@@ -180,7 +180,7 @@ function AlertDialogContent(t0) {
|
|
|
180
180
|
let t5;
|
|
181
181
|
if ($[7] !== props || $[8] !== size || $[9] !== t4) {
|
|
182
182
|
t5 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t3, /* @__PURE__ */ _jsx(MotionSlot, {
|
|
183
|
-
kind: "
|
|
183
|
+
kind: "dialog",
|
|
184
184
|
children: /* @__PURE__ */ _jsx(AlertDialogPrimitive.Content, {
|
|
185
185
|
forceMount: true,
|
|
186
186
|
"data-slot": "alert-dialog-content",
|
|
@@ -4,7 +4,7 @@ import { c as _c } from "react/compiler-runtime";
|
|
|
4
4
|
* Arc's Dialog surface (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md), shared by `Dialog` and
|
|
5
5
|
* `AlertDialog`: the dimmed, blurred overlay, the raised panel with Arc's surface radius, border and floating shadow,
|
|
6
6
|
* the title and description type, the bordered close button and the text swap that animates a title or description
|
|
7
|
-
* changed while the dialog is open. Internal: the
|
|
7
|
+
* changed while the dialog is open. Internal: the panel's entrance and exit are Arc's, played by `MotionSlot`.
|
|
8
8
|
*/
|
|
9
9
|
import { AnimatePresence, motion, useIsPresent } from "motion/react";
|
|
10
10
|
import { DIALOG_TEXT_SWAP_OFFSET_EM } from "../constants/dialog.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Arc's Dialog (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): a focused surface for decisions that need
|
|
3
3
|
* attention, on Arc's overlay, raised panel, title and description type and bordered close button, with Arc's swap of
|
|
4
|
-
* a title or description changed while open
|
|
5
|
-
*
|
|
4
|
+
* a title or description changed while open, and Arc's dialog transition: the panel rises and scales in on the smooth
|
|
5
|
+
* spring and leaves quickly. It keeps beez-ui's composable parts and the viewport close button placement instead of
|
|
6
|
+
* Arc's single `title`/`description` content.
|
|
6
7
|
*/
|
|
7
8
|
import * as React from "react";
|
|
8
9
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
@@ -14,8 +15,8 @@ declare function DialogOverlay({ className, ...props }: React.ComponentProps<typ
|
|
|
14
15
|
/** Where the dialog close button sits: inside the panel or pinned to the viewport corner. */
|
|
15
16
|
type DialogCloseButtonPlacement = "content" | "viewport";
|
|
16
17
|
/**
|
|
17
|
-
* Renders compact dialog content with viewport-safe scrolling. The panel
|
|
18
|
-
*
|
|
18
|
+
* Renders compact dialog content with viewport-safe scrolling. The panel rises 8px and scales
|
|
19
|
+
* from 0.96 on Arc's smooth spring while it fades in, and leaves with a short drop and fade.
|
|
19
20
|
* @param props - Primitive properties and optional consumer overrides.
|
|
20
21
|
* @param props.showCloseButton - Whether the dialog renders its own close button.
|
|
21
22
|
* @param props.closeButtonPlacement - `viewport` pins the close button to the viewport corner
|
|
@@ -3,8 +3,9 @@ import { c as _c } from "react/compiler-runtime";
|
|
|
3
3
|
/**
|
|
4
4
|
* Arc's Dialog (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): a focused surface for decisions that need
|
|
5
5
|
* attention, on Arc's overlay, raised panel, title and description type and bordered close button, with Arc's swap of
|
|
6
|
-
* a title or description changed while open
|
|
7
|
-
*
|
|
6
|
+
* a title or description changed while open, and Arc's dialog transition: the panel rises and scales in on the smooth
|
|
7
|
+
* spring and leaves quickly. It keeps beez-ui's composable parts and the viewport close button placement instead of
|
|
8
|
+
* Arc's single `title`/`description` content.
|
|
8
9
|
*/
|
|
9
10
|
import * as React from "react";
|
|
10
11
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
@@ -165,7 +166,7 @@ function DialogOverlay(t0) {
|
|
|
165
166
|
}
|
|
166
167
|
/**
|
|
167
168
|
* Renders a close button pinned to the viewport corner. It stays hidden while the panel
|
|
168
|
-
*
|
|
169
|
+
* enters, because the entrance transform would otherwise carry it along with the panel, and
|
|
169
170
|
* fades in once the panel settles. It hides at once when the dialog starts closing.
|
|
170
171
|
* While hidden it is also `visibility: hidden`, so the dialog's initial focus and the
|
|
171
172
|
* keyboard can never land on a control that cannot be seen.
|
|
@@ -202,8 +203,8 @@ function DialogViewportCloseButton() {
|
|
|
202
203
|
return t1;
|
|
203
204
|
}
|
|
204
205
|
/**
|
|
205
|
-
* Renders compact dialog content with viewport-safe scrolling. The panel
|
|
206
|
-
*
|
|
206
|
+
* Renders compact dialog content with viewport-safe scrolling. The panel rises 8px and scales
|
|
207
|
+
* from 0.96 on Arc's smooth spring while it fades in, and leaves with a short drop and fade.
|
|
207
208
|
* @param props - Primitive properties and optional consumer overrides.
|
|
208
209
|
* @param props.showCloseButton - Whether the dialog renders its own close button.
|
|
209
210
|
* @param props.closeButtonPlacement - `viewport` pins the close button to the viewport corner
|
|
@@ -300,7 +301,7 @@ function DialogContent(t0) {
|
|
|
300
301
|
let t11;
|
|
301
302
|
if ($[18] !== children || $[19] !== props || $[20] !== t10 || $[21] !== t5 || $[22] !== t7 || $[23] !== t8 || $[24] !== t9) {
|
|
302
303
|
t11 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t4, /* @__PURE__ */ _jsx(MotionSlot, {
|
|
303
|
-
kind: "
|
|
304
|
+
kind: "dialog",
|
|
304
305
|
children: /* @__PURE__ */ _jsxs(DialogPrimitive.Content, {
|
|
305
306
|
forceMount: true,
|
|
306
307
|
"data-slot": "dialog-content",
|
|
@@ -20,7 +20,7 @@ const LINK_REL = "noreferrer";
|
|
|
20
20
|
* text below 16px, so the editor and the inputs are pinned to 1rem on phones.
|
|
21
21
|
*/
|
|
22
22
|
const RICH_LINK_EDITOR_CLASS_NAMES = {
|
|
23
|
-
editor: "min-h-28 w-full cursor-text border-0 bg-
|
|
23
|
+
editor: "min-h-28 w-full cursor-text border-0 bg-transparent p-0 leading-[1.65] whitespace-pre-wrap text-foreground [font:inherit] [overflow-wrap:anywhere] focus:outline-0 empty:before:pointer-events-none empty:before:text-muted-foreground/75 empty:before:content-[attr(data-placeholder)] max-md:text-base",
|
|
24
24
|
editorInvalid: "rounded-[0.35rem] shadow-[inset_0_-2px_0_var(--destructive)] outline-0",
|
|
25
25
|
editorLink: "cursor-pointer rounded-[0.2rem] font-medium text-primary underline decoration-[0.08em] underline-offset-[0.18em] transition-colors hover:text-[color-mix(in_oklab,var(--primary)_72%,var(--foreground))] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
|
|
26
26
|
popover: "gap-3",
|
|
@@ -20,7 +20,7 @@ import { SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME } from "../constants/sideba
|
|
|
20
20
|
import { cn } from "../lib/utils.js";
|
|
21
21
|
import { MotionSlot } from "../motion/motion-slot.js";
|
|
22
22
|
import { SharedLayoutBg } from "../motion/shared-layout-bg.js";
|
|
23
|
-
import { MOTION_EASE, MOTION_EASE_DRAWER, MOTION_LIST_ITEM_DISTANCE, MOTION_TIMING, SPRING_LAYOUT } from "../motion/tokens.js";
|
|
23
|
+
import { MOTION_EASE, MOTION_EASE_DRAWER, MOTION_LIST_ITEM_DISTANCE, MOTION_TIMING, SPRING_LAYOUT, SPRING_PANEL } from "../motion/tokens.js";
|
|
24
24
|
import { Link } from "./link.js";
|
|
25
25
|
import { SidebarPanelContext } from "./sidebar-panel-context.js";
|
|
26
26
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -42,15 +42,10 @@ const PANEL_TRANSITION = {
|
|
|
42
42
|
ease: MOTION_EASE_DRAWER
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
|
-
* The desktop rail settles at a hard zero-width boundary
|
|
46
|
-
* cannot overshoot, pause against that boundary
|
|
45
|
+
* The desktop rail settles at a hard zero-width boundary, and its width reports the panel state. Arc's smooth spring
|
|
46
|
+
* is critically damped, so it cannot overshoot, pause against that boundary and snap back during the final frame.
|
|
47
47
|
*/
|
|
48
|
-
const SIDEBAR_MORPH_TRANSITION =
|
|
49
|
-
type: "spring",
|
|
50
|
-
stiffness: 380,
|
|
51
|
-
damping: 35,
|
|
52
|
-
mass: .75
|
|
53
|
-
};
|
|
48
|
+
const SIDEBAR_MORPH_TRANSITION = SPRING_PANEL;
|
|
54
49
|
const LABEL_ENTER_TRANSITION = {
|
|
55
50
|
duration: MOTION_TIMING.message,
|
|
56
51
|
delay: .08,
|
|
@@ -8,11 +8,14 @@ export declare const ARC_DURATION: {
|
|
|
8
8
|
readonly fast: 0.16;
|
|
9
9
|
readonly exit: 0.18;
|
|
10
10
|
readonly standard: 0.24;
|
|
11
|
+
readonly considered: 0.48;
|
|
11
12
|
};
|
|
12
|
-
/** Cubic-bezier curves
|
|
13
|
+
/** Cubic-bezier curves: entrances, exits, color or opacity tweens, and moves of elements already on screen. */
|
|
13
14
|
export declare const ARC_EASE: {
|
|
14
15
|
readonly enter: readonly [0.16, 1, 0.3, 1];
|
|
16
|
+
readonly exit: readonly [0.7, 0, 0.84, 0];
|
|
15
17
|
readonly standard: readonly [0.22, 1, 0.36, 1];
|
|
18
|
+
readonly inOut: readonly [0.65, 0, 0.35, 1];
|
|
16
19
|
};
|
|
17
20
|
/** Presses, toggles and small indicators: settles fast with a hint of life. */
|
|
18
21
|
export declare const ARC_SPRING_SNAPPY: {
|
|
@@ -35,6 +38,7 @@ export declare const ARC_SPRING_MORPH: {
|
|
|
35
38
|
/** Stagger steps in seconds; keep a whole staggered entrance under roughly 0.4s. */
|
|
36
39
|
export declare const ARC_STAGGER: {
|
|
37
40
|
readonly char: 0.016;
|
|
41
|
+
readonly item: 0.035;
|
|
38
42
|
};
|
|
39
43
|
/** Blur radii in pixels for brief content crossfades. */
|
|
40
44
|
export declare const ARC_BLUR: {
|
|
@@ -7,9 +7,10 @@ export const ARC_DURATION = {
|
|
|
7
7
|
instant: .12,
|
|
8
8
|
fast: .16,
|
|
9
9
|
exit: .18,
|
|
10
|
-
standard: .24
|
|
10
|
+
standard: .24,
|
|
11
|
+
considered: .48
|
|
11
12
|
};
|
|
12
|
-
/** Cubic-bezier curves
|
|
13
|
+
/** Cubic-bezier curves: entrances, exits, color or opacity tweens, and moves of elements already on screen. */
|
|
13
14
|
export const ARC_EASE = {
|
|
14
15
|
enter: [
|
|
15
16
|
.16,
|
|
@@ -17,11 +18,23 @@ export const ARC_EASE = {
|
|
|
17
18
|
.3,
|
|
18
19
|
1
|
|
19
20
|
],
|
|
21
|
+
exit: [
|
|
22
|
+
.7,
|
|
23
|
+
0,
|
|
24
|
+
.84,
|
|
25
|
+
0
|
|
26
|
+
],
|
|
20
27
|
standard: [
|
|
21
28
|
.22,
|
|
22
29
|
1,
|
|
23
30
|
.36,
|
|
24
31
|
1
|
|
32
|
+
],
|
|
33
|
+
inOut: [
|
|
34
|
+
.65,
|
|
35
|
+
0,
|
|
36
|
+
.35,
|
|
37
|
+
1
|
|
25
38
|
]
|
|
26
39
|
};
|
|
27
40
|
/** Presses, toggles and small indicators: settles fast with a hint of life. */
|
|
@@ -43,7 +56,10 @@ export const ARC_SPRING_MORPH = {
|
|
|
43
56
|
bounce: .16
|
|
44
57
|
};
|
|
45
58
|
/** Stagger steps in seconds; keep a whole staggered entrance under roughly 0.4s. */
|
|
46
|
-
export const ARC_STAGGER = {
|
|
59
|
+
export const ARC_STAGGER = {
|
|
60
|
+
char: .016,
|
|
61
|
+
item: .035
|
|
62
|
+
};
|
|
47
63
|
/** Blur radii in pixels for brief content crossfades. */
|
|
48
64
|
export const ARC_BLUR = {
|
|
49
65
|
subtle: 2,
|
|
@@ -55,9 +55,8 @@ export declare const GLIDE_PRESETS: {
|
|
|
55
55
|
surface: () => "background";
|
|
56
56
|
spring: {
|
|
57
57
|
readonly type: "spring";
|
|
58
|
-
readonly
|
|
59
|
-
readonly
|
|
60
|
-
readonly mass: 0.5;
|
|
58
|
+
readonly visualDuration: 0.26;
|
|
59
|
+
readonly bounce: 0.12;
|
|
61
60
|
};
|
|
62
61
|
instantOnPointer: true;
|
|
63
62
|
};
|
|
@@ -69,9 +68,8 @@ export declare const GLIDE_PRESETS: {
|
|
|
69
68
|
surface: () => "background";
|
|
70
69
|
spring: {
|
|
71
70
|
readonly type: "spring";
|
|
72
|
-
readonly
|
|
73
|
-
readonly
|
|
74
|
-
readonly mass: 0.5;
|
|
71
|
+
readonly visualDuration: 0.26;
|
|
72
|
+
readonly bounce: 0.12;
|
|
75
73
|
};
|
|
76
74
|
instantOnPointer: true;
|
|
77
75
|
};
|
|
@@ -47,42 +47,81 @@ export const GLIDE_PRESETS = {
|
|
|
47
47
|
export const GLIDE_TARGET_ATTRIBUTE = "data-glide-target";
|
|
48
48
|
/** Marks items whose transitions, including pseudo-element ones, are suspended during a glide. */
|
|
49
49
|
export const GLIDE_FREEZE_ATTRIBUTE = "data-glide-freeze";
|
|
50
|
-
/**
|
|
50
|
+
/** Laid-out size of the border box, unaffected by any transform on the element or its ancestors. */
|
|
51
|
+
function layoutSize(element) {
|
|
52
|
+
const style = getComputedStyle(element);
|
|
53
|
+
const width = Number.parseFloat(style.width);
|
|
54
|
+
const height = Number.parseFloat(style.height);
|
|
55
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) {
|
|
56
|
+
return {
|
|
57
|
+
width: element.offsetWidth,
|
|
58
|
+
height: element.offsetHeight
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (style.boxSizing === "border-box") return {
|
|
62
|
+
width,
|
|
63
|
+
height
|
|
64
|
+
};
|
|
65
|
+
const sum = (...values) => values.reduce((total, value) => total + (Number.parseFloat(value) || 0), 0);
|
|
66
|
+
return {
|
|
67
|
+
width: width + sum(style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth),
|
|
68
|
+
height: height + sum(style.paddingTop, style.paddingBottom, style.borderTopWidth, style.borderBottomWidth)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Converts a viewport rectangle into the container's own scrolling coordinate space. A container
|
|
73
|
+
* still scaling in (a menu or listbox entrance) paints everything inside it smaller, so painted
|
|
74
|
+
* distances are divided by that scale to land where absolute positioning places the copy.
|
|
75
|
+
*/
|
|
51
76
|
function toContainerBox(container, rect) {
|
|
52
77
|
const origin = container.getBoundingClientRect();
|
|
78
|
+
const layout = layoutSize(container);
|
|
79
|
+
const scaleX = layout.width > 0 && origin.width > 0 ? origin.width / layout.width : 1;
|
|
80
|
+
const scaleY = layout.height > 0 && origin.height > 0 ? origin.height / layout.height : 1;
|
|
53
81
|
return {
|
|
54
|
-
left: rect.left - origin.left - container.clientLeft + container.scrollLeft,
|
|
55
|
-
top: rect.top - origin.top - container.clientTop + container.scrollTop,
|
|
56
|
-
width: rect.width,
|
|
57
|
-
height: rect.height
|
|
82
|
+
left: (rect.left - origin.left) / scaleX - container.clientLeft + container.scrollLeft,
|
|
83
|
+
top: (rect.top - origin.top) / scaleY - container.clientTop + container.scrollTop,
|
|
84
|
+
width: rect.width / scaleX,
|
|
85
|
+
height: rect.height / scaleY
|
|
58
86
|
};
|
|
59
87
|
}
|
|
60
|
-
/**
|
|
61
|
-
function
|
|
62
|
-
const
|
|
88
|
+
/** Scale and translation an item's own running entrance adds, read from its computed `matrix()`. */
|
|
89
|
+
function inFlightTransform(item) {
|
|
90
|
+
const style = getComputedStyle(item);
|
|
91
|
+
const values = /^matrix\(([^)]+)\)$/.exec(style.transform);
|
|
92
|
+
const [originX = 0, originY = 0] = style.transformOrigin.split(" ").map(Number.parseFloat);
|
|
63
93
|
if (!values) return {
|
|
94
|
+
scaleX: 1,
|
|
95
|
+
scaleY: 1,
|
|
64
96
|
x: 0,
|
|
65
|
-
y: 0
|
|
97
|
+
y: 0,
|
|
98
|
+
originX,
|
|
99
|
+
originY
|
|
66
100
|
};
|
|
67
101
|
const parts = values[1].split(",").map(Number.parseFloat);
|
|
68
102
|
return {
|
|
103
|
+
scaleX: parts[0] || 1,
|
|
104
|
+
scaleY: parts[3] || 1,
|
|
69
105
|
x: parts[4] ?? 0,
|
|
70
|
-
y: parts[5] ?? 0
|
|
106
|
+
y: parts[5] ?? 0,
|
|
107
|
+
originX,
|
|
108
|
+
originY
|
|
71
109
|
};
|
|
72
110
|
}
|
|
73
111
|
/**
|
|
74
|
-
* Measures the highlight: the item box, or its positioned `::after`
|
|
75
|
-
* An item still
|
|
76
|
-
*
|
|
112
|
+
* Measures the highlight in the container's coordinates: the item box, or its positioned `::after`
|
|
113
|
+
* bar for line variants. An item still entering (Select options settle from a slight scale) is
|
|
114
|
+
* measured where it will rest, so the highlight neither lands undersized nor jumps when it ends.
|
|
77
115
|
*/
|
|
78
|
-
function highlightBox(item, surface) {
|
|
79
|
-
const
|
|
80
|
-
const
|
|
116
|
+
function highlightBox(container, item, surface) {
|
|
117
|
+
const painted = toContainerBox(container, item.getBoundingClientRect());
|
|
118
|
+
const motion = inFlightTransform(item);
|
|
119
|
+
// The entrance scales around the transform origin, so the resting corner sits that far back.
|
|
81
120
|
const rect = {
|
|
82
|
-
left:
|
|
83
|
-
top:
|
|
84
|
-
width:
|
|
85
|
-
height:
|
|
121
|
+
left: painted.left - motion.x - motion.originX * (1 - motion.scaleX),
|
|
122
|
+
top: painted.top - motion.y - motion.originY * (1 - motion.scaleY),
|
|
123
|
+
width: painted.width / motion.scaleX,
|
|
124
|
+
height: painted.height / motion.scaleY
|
|
86
125
|
};
|
|
87
126
|
if (surface === "background") return rect;
|
|
88
127
|
const pseudo = getComputedStyle(item, "::after");
|
|
@@ -201,13 +240,13 @@ export function attachGlideIndicator(container, preset) {
|
|
|
201
240
|
/** Starts, or redirects, the glide from the previous highlight to the new active item. */
|
|
202
241
|
function glide(from, to) {
|
|
203
242
|
const surface = preset.surface(container);
|
|
204
|
-
const
|
|
243
|
+
const start = overlay ? toContainerBox(container, overlay.getBoundingClientRect()) : highlightBox(container, from, surface);
|
|
205
244
|
settle();
|
|
206
245
|
// The previous item drops its highlight instantly: the copy is what leaves it.
|
|
207
246
|
freezeTransitions(from)();
|
|
208
247
|
// Read the target's settled paint before any transition has a chance to start.
|
|
209
248
|
const thawTarget = freezeTransitions(to);
|
|
210
|
-
const destination =
|
|
249
|
+
const destination = highlightBox(container, to, surface);
|
|
211
250
|
const paint = highlightPaint(to, surface);
|
|
212
251
|
if (destination.width === 0 || destination.height === 0) {
|
|
213
252
|
thawTarget();
|
|
@@ -227,7 +266,6 @@ export function attachGlideIndicator(container, preset) {
|
|
|
227
266
|
zIndex: "-1",
|
|
228
267
|
margin: "0"
|
|
229
268
|
});
|
|
230
|
-
const start = toContainerBox(container, origin);
|
|
231
269
|
container.prepend(overlay);
|
|
232
270
|
releaseTarget = hideTarget(to, surface, thawTarget);
|
|
233
271
|
animation = animate(overlay, {
|