@astra-kit/ui 0.0.0-stage → 0.0.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/CHANGELOG.md +15 -0
- package/LICENSE.md +21 -0
- package/README.md +384 -2
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/assets/fonts/geist-LICENSE.txt +93 -0
- package/assets/fonts/geist-latin-variable.woff2 +0 -0
- package/assets/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
- package/assets/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
- package/assets/fonts/ibmplexmono-LICENSE.txt +93 -0
- package/assets/fonts/inter-LICENSE.txt +93 -0
- package/assets/fonts/inter-latin-variable.woff2 +0 -0
- package/dist/adapters/unpic-image.d.ts +3 -0
- package/dist/adapters/unpic-image.js +98 -0
- package/dist/components/account-menu.d.ts +67 -0
- package/dist/components/account-menu.js +440 -0
- package/dist/components/action-button.d.ts +25 -0
- package/dist/components/action-button.js +264 -0
- package/dist/components/alert.d.ts +31 -0
- package/dist/components/alert.js +503 -0
- package/dist/components/animated-collapse.d.ts +19 -0
- package/dist/components/animated-collapse.js +170 -0
- package/dist/components/animated-count.d.ts +13 -0
- package/dist/components/animated-count.js +105 -0
- package/dist/components/animated-list-item.d.ts +25 -0
- package/dist/components/animated-list-item.js +134 -0
- package/dist/components/animated-theme-toggler.d.ts +12 -0
- package/dist/components/animated-theme-toggler.js +200 -0
- package/dist/components/avatar.d.ts +65 -0
- package/dist/components/avatar.js +463 -0
- package/dist/components/badge.d.ts +21 -0
- package/dist/components/badge.js +297 -0
- package/dist/components/button-interaction.d.ts +23 -0
- package/dist/components/button-interaction.js +22 -0
- package/dist/components/button-label.d.ts +8 -0
- package/dist/components/button-label.js +203 -0
- package/dist/components/button.d.ts +23 -0
- package/dist/components/button.js +145 -0
- package/dist/components/calendar.d.ts +47 -0
- package/dist/components/calendar.js +155 -0
- package/dist/components/card.d.ts +38 -0
- package/dist/components/card.js +904 -0
- package/dist/components/carousel.d.ts +71 -0
- package/dist/components/carousel.js +585 -0
- package/dist/components/checkbox.d.ts +15 -0
- package/dist/components/checkbox.js +324 -0
- package/dist/components/control-button.d.ts +16 -0
- package/dist/components/control-button.js +215 -0
- package/dist/components/data-table.d.ts +118 -0
- package/dist/components/data-table.js +895 -0
- package/dist/components/dialog-surface.d.ts +49 -0
- package/dist/components/dialog-surface.js +220 -0
- package/dist/components/dialog.d.ts +92 -0
- package/dist/components/dialog.js +320 -0
- package/dist/components/dropdown-menu.d.ts +57 -0
- package/dist/components/dropdown-menu.js +107 -0
- package/dist/components/field.d.ts +53 -0
- package/dist/components/field.js +710 -0
- package/dist/components/file-upload.d.ts +88 -0
- package/dist/components/file-upload.js +776 -0
- package/dist/components/filter-presets-bar.d.ts +73 -0
- package/dist/components/filter-presets-bar.js +510 -0
- package/dist/components/filter-query-bar.d.ts +21 -0
- package/dist/components/filter-query-bar.js +881 -0
- package/dist/components/filter-query-grammar.d.ts +188 -0
- package/dist/components/filter-query-grammar.js +875 -0
- package/dist/components/form.d.ts +29 -0
- package/dist/components/form.js +330 -0
- package/dist/components/highlighter.d.ts +15 -0
- package/dist/components/highlighter.js +152 -0
- package/dist/components/hover-card.d.ts +50 -0
- package/dist/components/hover-card.js +80 -0
- package/dist/components/input-group.d.ts +16 -0
- package/dist/components/input-group.js +277 -0
- package/dist/components/input.d.ts +17 -0
- package/dist/components/input.js +120 -0
- package/dist/components/label.d.ts +4 -0
- package/dist/components/label.js +43 -0
- package/dist/components/link.d.ts +9 -0
- package/dist/components/link.js +43 -0
- package/dist/components/morph-text.d.ts +14 -0
- package/dist/components/morph-text.js +210 -0
- package/dist/components/pagination.d.ts +59 -0
- package/dist/components/pagination.js +190 -0
- package/dist/components/popover.d.ts +17 -0
- package/dist/components/popover.js +40 -0
- package/dist/components/presence-swap.d.ts +22 -0
- package/dist/components/presence-swap.js +209 -0
- package/dist/components/primitives/alert-dialog.d.ts +68 -0
- package/dist/components/primitives/alert-dialog.js +629 -0
- package/dist/components/primitives/avatar.d.ts +46 -0
- package/dist/components/primitives/avatar.js +265 -0
- package/dist/components/primitives/calendar.d.ts +37 -0
- package/dist/components/primitives/calendar.js +1250 -0
- package/dist/components/primitives/carousel.d.ts +106 -0
- package/dist/components/primitives/carousel.js +928 -0
- package/dist/components/primitives/dialog.d.ts +62 -0
- package/dist/components/primitives/dialog.js +490 -0
- package/dist/components/primitives/dropdown-menu-items.d.ts +59 -0
- package/dist/components/primitives/dropdown-menu-items.js +265 -0
- package/dist/components/primitives/dropdown-menu.d.ts +64 -0
- package/dist/components/primitives/dropdown-menu.js +560 -0
- package/dist/components/primitives/hover-card.d.ts +50 -0
- package/dist/components/primitives/hover-card.js +507 -0
- package/dist/components/primitives/pagination.d.ts +65 -0
- package/dist/components/primitives/pagination.js +373 -0
- package/dist/components/primitives/popover.d.ts +22 -0
- package/dist/components/primitives/popover.js +213 -0
- package/dist/components/primitives/select.d.ts +37 -0
- package/dist/components/primitives/select.js +428 -0
- package/dist/components/primitives/tooltip.d.ts +30 -0
- package/dist/components/primitives/tooltip.js +277 -0
- package/dist/components/progress-ring.d.ts +20 -0
- package/dist/components/progress-ring.js +53 -0
- package/dist/components/radio-group.d.ts +34 -0
- package/dist/components/radio-group.js +392 -0
- package/dist/components/reaction-button.d.ts +30 -0
- package/dist/components/reaction-button.js +189 -0
- package/dist/components/rich-link-editor.d.ts +25 -0
- package/dist/components/rich-link-editor.js +320 -0
- package/dist/components/rich-markdown-content.d.ts +10 -0
- package/dist/components/rich-markdown-content.js +56 -0
- package/dist/components/rich-text-content.d.ts +19 -0
- package/dist/components/rich-text-content.js +26 -0
- package/dist/components/select.d.ts +55 -0
- package/dist/components/select.js +188 -0
- package/dist/components/separator.d.ts +3 -0
- package/dist/components/separator.js +48 -0
- package/dist/components/sheet.d.ts +19 -0
- package/dist/components/sheet.js +420 -0
- package/dist/components/sidebar-panel-context.d.ts +17 -0
- package/dist/components/sidebar-panel-context.js +14 -0
- package/dist/components/sidebar.d.ts +195 -0
- package/dist/components/sidebar.js +2041 -0
- package/dist/components/skeleton.d.ts +23 -0
- package/dist/components/skeleton.js +334 -0
- package/dist/components/split-button.d.ts +36 -0
- package/dist/components/split-button.js +306 -0
- package/dist/components/svgs/whatsappIcon.d.ts +3 -0
- package/dist/components/svgs/whatsappIcon.js +14 -0
- package/dist/components/switch.d.ts +13 -0
- package/dist/components/switch.js +444 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/table.js +298 -0
- package/dist/components/tabs.d.ts +36 -0
- package/dist/components/tabs.js +636 -0
- package/dist/components/textarea.d.ts +16 -0
- package/dist/components/textarea.js +111 -0
- package/dist/components/themed-toaster.d.ts +7 -0
- package/dist/components/themed-toaster.js +86 -0
- package/dist/components/toaster.d.ts +12 -0
- package/dist/components/toaster.js +62 -0
- package/dist/components/tooltip.d.ts +43 -0
- package/dist/components/tooltip.js +65 -0
- package/dist/components/typing-animation.d.ts +34 -0
- package/dist/components/typing-animation.js +389 -0
- package/dist/constants/action-button.d.ts +20 -0
- package/dist/constants/action-button.js +17 -0
- package/dist/constants/alert.d.ts +16 -0
- package/dist/constants/alert.js +13 -0
- package/dist/constants/avatar.d.ts +38 -0
- package/dist/constants/avatar.js +32 -0
- package/dist/constants/badge.d.ts +6 -0
- package/dist/constants/badge.js +6 -0
- package/dist/constants/button.d.ts +16 -0
- package/dist/constants/button.js +16 -0
- package/dist/constants/calendar.d.ts +36 -0
- package/dist/constants/calendar.js +34 -0
- package/dist/constants/card.d.ts +23 -0
- package/dist/constants/card.js +20 -0
- package/dist/constants/carousel.d.ts +55 -0
- package/dist/constants/carousel.js +74 -0
- package/dist/constants/checkbox.d.ts +17 -0
- package/dist/constants/checkbox.js +17 -0
- package/dist/constants/dialog.d.ts +11 -0
- package/dist/constants/dialog.js +10 -0
- package/dist/constants/dropdown-menu.d.ts +10 -0
- package/dist/constants/dropdown-menu.js +37 -0
- package/dist/constants/field.d.ts +24 -0
- package/dist/constants/field.js +24 -0
- package/dist/constants/hover-card.d.ts +37 -0
- package/dist/constants/hover-card.js +85 -0
- package/dist/constants/morph-text.d.ts +13 -0
- package/dist/constants/morph-text.js +13 -0
- package/dist/constants/motion.d.ts +12 -0
- package/dist/constants/motion.js +12 -0
- package/dist/constants/pagination.d.ts +20 -0
- package/dist/constants/pagination.js +20 -0
- package/dist/constants/popover.d.ts +7 -0
- package/dist/constants/popover.js +33 -0
- package/dist/constants/radio-group.d.ts +10 -0
- package/dist/constants/radio-group.js +10 -0
- package/dist/constants/select.d.ts +7 -0
- package/dist/constants/select.js +34 -0
- package/dist/constants/sidebar.d.ts +9 -0
- package/dist/constants/sidebar.js +17 -0
- package/dist/constants/skeleton.d.ts +17 -0
- package/dist/constants/skeleton.js +17 -0
- package/dist/constants/split-button.d.ts +7 -0
- package/dist/constants/split-button.js +5 -0
- package/dist/constants/switch.d.ts +33 -0
- package/dist/constants/switch.js +41 -0
- package/dist/constants/tabs.d.ts +17 -0
- package/dist/constants/tabs.js +17 -0
- package/dist/constants/toast.d.ts +3 -0
- package/dist/constants/toast.js +3 -0
- package/dist/constants/tooltip.d.ts +13 -0
- package/dist/constants/tooltip.js +52 -0
- package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
- package/dist/hooks/use-horizontal-swipe.js +80 -0
- package/dist/hooks/use-is-hydrated.d.ts +6 -0
- package/dist/hooks/use-is-hydrated.js +20 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-prefers-reduced-motion.d.ts +2 -0
- package/dist/hooks/use-prefers-reduced-motion.js +27 -0
- package/dist/hooks/use-rich-link-editor.d.ts +55 -0
- package/dist/hooks/use-rich-link-editor.js +515 -0
- package/dist/hooks/use-sidebar-persistence.d.ts +6 -0
- package/dist/hooks/use-sidebar-persistence.js +52 -0
- package/dist/hooks/use-today.d.ts +7 -0
- package/dist/hooks/use-today.js +50 -0
- package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
- package/dist/hooks/use-viewer-time-zone.js +20 -0
- package/dist/hooks.d.ts +11 -0
- package/dist/hooks.js +11 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +69 -0
- package/dist/lib/browser-clipboard.d.ts +13 -0
- package/dist/lib/browser-clipboard.js +48 -0
- package/dist/lib/column-filter-value.d.ts +12 -0
- package/dist/lib/column-filter-value.js +52 -0
- package/dist/lib/file-acceptance.d.ts +43 -0
- package/dist/lib/file-acceptance.js +107 -0
- package/dist/lib/format-file-size.d.ts +16 -0
- package/dist/lib/format-file-size.js +34 -0
- package/dist/lib/fuzzy-search.d.ts +17 -0
- package/dist/lib/fuzzy-search.js +183 -0
- package/dist/lib/horizontal-swipe.d.ts +23 -0
- package/dist/lib/horizontal-swipe.js +29 -0
- package/dist/lib/image-dimensions.d.ts +2 -0
- package/dist/lib/image-dimensions.js +7 -0
- package/dist/lib/name-initials.d.ts +7 -0
- package/dist/lib/name-initials.js +11 -0
- package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
- package/dist/lib/rich-text/link-markdown-constants.js +458 -0
- package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
- package/dist/lib/rich-text/link-markdown-types.js +1 -0
- package/dist/lib/rich-text/link-markdown.d.ts +193 -0
- package/dist/lib/rich-text/link-markdown.js +592 -0
- package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
- package/dist/lib/rich-text/rich-markdown.js +105 -0
- package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
- package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
- package/dist/lib/toast-layer.d.ts +24 -0
- package/dist/lib/toast-layer.js +76 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +2 -0
- package/dist/lib/year-month-filter.d.ts +16 -0
- package/dist/lib/year-month-filter.js +46 -0
- package/dist/motion/arc-floating-slot.d.ts +40 -0
- package/dist/motion/arc-floating-slot.js +177 -0
- package/dist/motion/arc-press.d.ts +6 -0
- package/dist/motion/arc-press.js +59 -0
- package/dist/motion/arc-swap.d.ts +22 -0
- package/dist/motion/arc-swap.js +49 -0
- package/dist/motion/arc-tokens.d.ts +53 -0
- package/dist/motion/arc-tokens.js +73 -0
- package/dist/motion/glide-indicator.d.ts +69 -0
- package/dist/motion/glide-indicator.js +309 -0
- package/dist/motion/glide-slot.d.ts +9 -0
- package/dist/motion/glide-slot.js +71 -0
- package/dist/motion/motion-slot.d.ts +12 -0
- package/dist/motion/motion-slot.js +376 -0
- package/dist/motion/overlay-warmth.d.ts +24 -0
- package/dist/motion/overlay-warmth.js +70 -0
- package/dist/motion/presence.d.ts +40 -0
- package/dist/motion/presence.js +101 -0
- package/dist/motion/surface-keyframes.d.ts +24 -0
- package/dist/motion/surface-keyframes.js +141 -0
- package/dist/motion/tokens.d.ts +81 -0
- package/dist/motion/tokens.js +67 -0
- package/dist/motion/use-attached-element.d.ts +7 -0
- package/dist/motion/use-attached-element.js +22 -0
- package/dist/motion/use-morph-width.d.ts +13 -0
- package/dist/motion/use-morph-width.js +59 -0
- package/dist/next.d.ts +14 -0
- package/dist/next.js +79 -0
- package/dist/providers/astra-ui-provider.d.ts +27 -0
- package/dist/providers/astra-ui-provider.js +100 -0
- package/dist/providers/native-provider.d.ts +4 -0
- package/dist/providers/native-provider.js +45 -0
- package/dist/sonner.d.ts +7 -0
- package/dist/sonner.js +8 -0
- package/dist/styles.css +2 -0
- package/dist/tanstack.d.ts +11 -0
- package/dist/tanstack.js +50 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.js +1 -0
- package/dist/types/data-table.d.ts +27 -0
- package/dist/types/data-table.js +1 -0
- package/fonts.css +5 -0
- package/package.json +450 -4
- package/styles.css +4 -0
- package/theme.css +248 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swap presets adapted from Arc (https://uiarc.dev), Copyright (c) 2026 Elia Kuratli, MIT License.
|
|
3
|
+
* The full license text ships in THIRD_PARTY_NOTICES.md. Internal: shared by the Arc-derived buttons to swap icons
|
|
4
|
+
* and labels in place.
|
|
5
|
+
*/
|
|
6
|
+
import type { TargetAndTransition, Transition } from "motion/react";
|
|
7
|
+
/** Resting pose every swapped element settles into. */
|
|
8
|
+
export declare const ARC_SWAP_REST: TargetAndTransition;
|
|
9
|
+
/** Outgoing elements leave faster than incoming ones arrive. */
|
|
10
|
+
export declare const ARC_SWAP_EXIT_TRANSITION: Transition;
|
|
11
|
+
/** An incoming icon grows out of a slight blur. */
|
|
12
|
+
export declare const ARC_ICON_ENTER: TargetAndTransition;
|
|
13
|
+
/** An outgoing icon shrinks back into the same blur. */
|
|
14
|
+
export declare const ARC_ICON_EXIT: TargetAndTransition;
|
|
15
|
+
/** Scale rides the spring; opacity and blur tween so blur never overshoots below zero. */
|
|
16
|
+
export declare const ARC_ICON_TRANSITION: Transition;
|
|
17
|
+
/** With reduced motion, every swap is an instant fade. */
|
|
18
|
+
export declare const ARC_REDUCED_TRANSITION: Transition;
|
|
19
|
+
/** Reduced-motion entrance: the resting pose, only faded out. */
|
|
20
|
+
export declare const ARC_REDUCED_ENTER: TargetAndTransition;
|
|
21
|
+
/** Reduced-motion exit: an instant fade. */
|
|
22
|
+
export declare const ARC_REDUCED_EXIT: TargetAndTransition;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ARC_BLUR, ARC_DURATION, ARC_EASE, ARC_SPRING_SNAPPY } from "./arc-tokens.js";
|
|
2
|
+
/** Resting pose every swapped element settles into. */
|
|
3
|
+
export const ARC_SWAP_REST = {
|
|
4
|
+
opacity: 1,
|
|
5
|
+
x: 0,
|
|
6
|
+
y: 0,
|
|
7
|
+
scale: 1,
|
|
8
|
+
filter: "blur(0px)"
|
|
9
|
+
};
|
|
10
|
+
/** Outgoing elements leave faster than incoming ones arrive. */
|
|
11
|
+
export const ARC_SWAP_EXIT_TRANSITION = {
|
|
12
|
+
duration: ARC_DURATION.fast,
|
|
13
|
+
ease: [...ARC_EASE.standard]
|
|
14
|
+
};
|
|
15
|
+
/** An incoming icon grows out of a slight blur. */
|
|
16
|
+
export const ARC_ICON_ENTER = {
|
|
17
|
+
opacity: 0,
|
|
18
|
+
scale: .6,
|
|
19
|
+
filter: `blur(${ARC_BLUR.subtle}px)`
|
|
20
|
+
};
|
|
21
|
+
/** An outgoing icon shrinks back into the same blur. */
|
|
22
|
+
export const ARC_ICON_EXIT = {
|
|
23
|
+
...ARC_ICON_ENTER,
|
|
24
|
+
transition: ARC_SWAP_EXIT_TRANSITION
|
|
25
|
+
};
|
|
26
|
+
/** Scale rides the spring; opacity and blur tween so blur never overshoots below zero. */
|
|
27
|
+
export const ARC_ICON_TRANSITION = {
|
|
28
|
+
...ARC_SPRING_SNAPPY,
|
|
29
|
+
opacity: {
|
|
30
|
+
duration: ARC_DURATION.fast,
|
|
31
|
+
ease: [...ARC_EASE.enter]
|
|
32
|
+
},
|
|
33
|
+
filter: {
|
|
34
|
+
duration: ARC_DURATION.fast,
|
|
35
|
+
ease: [...ARC_EASE.enter]
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
/** With reduced motion, every swap is an instant fade. */
|
|
39
|
+
export const ARC_REDUCED_TRANSITION = { duration: ARC_DURATION.instant };
|
|
40
|
+
/** Reduced-motion entrance: the resting pose, only faded out. */
|
|
41
|
+
export const ARC_REDUCED_ENTER = {
|
|
42
|
+
...ARC_SWAP_REST,
|
|
43
|
+
opacity: 0
|
|
44
|
+
};
|
|
45
|
+
/** Reduced-motion exit: an instant fade. */
|
|
46
|
+
export const ARC_REDUCED_EXIT = {
|
|
47
|
+
opacity: 0,
|
|
48
|
+
transition: ARC_REDUCED_TRANSITION
|
|
49
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Motion presets adapted from Arc (https://uiarc.dev), Copyright (c) 2026 Elia Kuratli, MIT License.
|
|
3
|
+
* The full license text ships in THIRD_PARTY_NOTICES.md. Internal: only Arc-derived components use these.
|
|
4
|
+
*/
|
|
5
|
+
/** Durations in seconds, from an instant color answer to a considered layout change. */
|
|
6
|
+
export declare const ARC_DURATION: {
|
|
7
|
+
readonly instant: 0.12;
|
|
8
|
+
readonly fast: 0.16;
|
|
9
|
+
readonly exit: 0.18;
|
|
10
|
+
readonly standard: 0.24;
|
|
11
|
+
readonly considered: 0.48;
|
|
12
|
+
};
|
|
13
|
+
/** Cubic-bezier curves: entrances, exits, color or opacity tweens, and moves of elements already on screen. */
|
|
14
|
+
export declare const ARC_EASE: {
|
|
15
|
+
readonly enter: readonly [0.16, 1, 0.3, 1];
|
|
16
|
+
readonly exit: readonly [0.7, 0, 0.84, 0];
|
|
17
|
+
readonly standard: readonly [0.22, 1, 0.36, 1];
|
|
18
|
+
readonly inOut: readonly [0.65, 0, 0.35, 1];
|
|
19
|
+
};
|
|
20
|
+
/** Presses, toggles and small indicators: settles fast with a hint of life. */
|
|
21
|
+
export declare const ARC_SPRING_SNAPPY: {
|
|
22
|
+
readonly type: "spring";
|
|
23
|
+
readonly visualDuration: 0.26;
|
|
24
|
+
readonly bounce: 0.12;
|
|
25
|
+
};
|
|
26
|
+
/** Panels, height changes and layout shifts: critically damped, never overshoots. */
|
|
27
|
+
export declare const ARC_SPRING_SMOOTH: {
|
|
28
|
+
readonly type: "spring";
|
|
29
|
+
readonly visualDuration: 0.4;
|
|
30
|
+
readonly bounce: 0;
|
|
31
|
+
};
|
|
32
|
+
/** Shape morphs and width changes that follow new content. */
|
|
33
|
+
export declare const ARC_SPRING_MORPH: {
|
|
34
|
+
readonly type: "spring";
|
|
35
|
+
readonly visualDuration: 0.42;
|
|
36
|
+
readonly bounce: 0.16;
|
|
37
|
+
};
|
|
38
|
+
/** Arc's CSS spring (`--ease-spring` over `--duration-spring`) as a Motion spring: a gentle overshoot that settles. */
|
|
39
|
+
export declare const ARC_SPRING_CSS: {
|
|
40
|
+
readonly type: "spring";
|
|
41
|
+
readonly visualDuration: 0.34;
|
|
42
|
+
readonly bounce: 0.15;
|
|
43
|
+
};
|
|
44
|
+
/** Stagger steps in seconds; keep a whole staggered entrance under roughly 0.4s. */
|
|
45
|
+
export declare const ARC_STAGGER: {
|
|
46
|
+
readonly char: 0.016;
|
|
47
|
+
readonly item: 0.035;
|
|
48
|
+
};
|
|
49
|
+
/** Blur radii in pixels for brief content crossfades. */
|
|
50
|
+
export declare const ARC_BLUR: {
|
|
51
|
+
readonly subtle: 2;
|
|
52
|
+
readonly soft: 4;
|
|
53
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Motion presets adapted from Arc (https://uiarc.dev), Copyright (c) 2026 Elia Kuratli, MIT License.
|
|
3
|
+
* The full license text ships in THIRD_PARTY_NOTICES.md. Internal: only Arc-derived components use these.
|
|
4
|
+
*/
|
|
5
|
+
/** Durations in seconds, from an instant color answer to a considered layout change. */
|
|
6
|
+
export const ARC_DURATION = {
|
|
7
|
+
instant: .12,
|
|
8
|
+
fast: .16,
|
|
9
|
+
exit: .18,
|
|
10
|
+
standard: .24,
|
|
11
|
+
considered: .48
|
|
12
|
+
};
|
|
13
|
+
/** Cubic-bezier curves: entrances, exits, color or opacity tweens, and moves of elements already on screen. */
|
|
14
|
+
export const ARC_EASE = {
|
|
15
|
+
enter: [
|
|
16
|
+
.16,
|
|
17
|
+
1,
|
|
18
|
+
.3,
|
|
19
|
+
1
|
|
20
|
+
],
|
|
21
|
+
exit: [
|
|
22
|
+
.7,
|
|
23
|
+
0,
|
|
24
|
+
.84,
|
|
25
|
+
0
|
|
26
|
+
],
|
|
27
|
+
standard: [
|
|
28
|
+
.22,
|
|
29
|
+
1,
|
|
30
|
+
.36,
|
|
31
|
+
1
|
|
32
|
+
],
|
|
33
|
+
inOut: [
|
|
34
|
+
.65,
|
|
35
|
+
0,
|
|
36
|
+
.35,
|
|
37
|
+
1
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
/** Presses, toggles and small indicators: settles fast with a hint of life. */
|
|
41
|
+
export const ARC_SPRING_SNAPPY = {
|
|
42
|
+
type: "spring",
|
|
43
|
+
visualDuration: .26,
|
|
44
|
+
bounce: .12
|
|
45
|
+
};
|
|
46
|
+
/** Panels, height changes and layout shifts: critically damped, never overshoots. */
|
|
47
|
+
export const ARC_SPRING_SMOOTH = {
|
|
48
|
+
type: "spring",
|
|
49
|
+
visualDuration: .4,
|
|
50
|
+
bounce: 0
|
|
51
|
+
};
|
|
52
|
+
/** Shape morphs and width changes that follow new content. */
|
|
53
|
+
export const ARC_SPRING_MORPH = {
|
|
54
|
+
type: "spring",
|
|
55
|
+
visualDuration: .42,
|
|
56
|
+
bounce: .16
|
|
57
|
+
};
|
|
58
|
+
/** Arc's CSS spring (`--ease-spring` over `--duration-spring`) as a Motion spring: a gentle overshoot that settles. */
|
|
59
|
+
export const ARC_SPRING_CSS = {
|
|
60
|
+
type: "spring",
|
|
61
|
+
visualDuration: .34,
|
|
62
|
+
bounce: .15
|
|
63
|
+
};
|
|
64
|
+
/** Stagger steps in seconds; keep a whole staggered entrance under roughly 0.4s. */
|
|
65
|
+
export const ARC_STAGGER = {
|
|
66
|
+
char: .016,
|
|
67
|
+
item: .035
|
|
68
|
+
};
|
|
69
|
+
/** Blur radii in pixels for brief content crossfades. */
|
|
70
|
+
export const ARC_BLUR = {
|
|
71
|
+
subtle: 2,
|
|
72
|
+
soft: 4
|
|
73
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ARC_SPRING_MORPH, ARC_SPRING_SNAPPY } from "./arc-tokens.js";
|
|
2
|
+
/** Which part of the active item carries the highlight that must travel. */
|
|
3
|
+
type GlideSurface = "background" | "after";
|
|
4
|
+
/** Describes the items of one container and how their active state is exposed. */
|
|
5
|
+
export interface GlidePreset {
|
|
6
|
+
itemSelector: string;
|
|
7
|
+
/**
|
|
8
|
+
* Matches the container and any nested container of the same kind, so items that belong to a
|
|
9
|
+
* nested one (a submenu rendered inside its parent menu) are left to that container's glide.
|
|
10
|
+
*/
|
|
11
|
+
containerSelector: string;
|
|
12
|
+
/** Attributes whose mutations can change which item is active. */
|
|
13
|
+
attributes: string[];
|
|
14
|
+
isActive: (item: Element) => boolean;
|
|
15
|
+
surface: (container: HTMLElement) => GlideSurface;
|
|
16
|
+
spring: typeof ARC_SPRING_MORPH | typeof ARC_SPRING_SNAPPY;
|
|
17
|
+
/**
|
|
18
|
+
* Arc's menu highlight glides between items for the pointer and jumps instantly for the
|
|
19
|
+
* keyboard, so a held arrow key never trails behind the focus.
|
|
20
|
+
*/
|
|
21
|
+
instantOnKeyboard?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare const GLIDE_PRESETS: {
|
|
24
|
+
tabs: {
|
|
25
|
+
itemSelector: string;
|
|
26
|
+
containerSelector: string;
|
|
27
|
+
attributes: string[];
|
|
28
|
+
isActive: (item: Element) => boolean;
|
|
29
|
+
surface: () => "background";
|
|
30
|
+
spring: {
|
|
31
|
+
readonly type: "spring";
|
|
32
|
+
readonly visualDuration: 0.42;
|
|
33
|
+
readonly bounce: 0.16;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
pagination: {
|
|
37
|
+
itemSelector: string;
|
|
38
|
+
containerSelector: string;
|
|
39
|
+
attributes: string[];
|
|
40
|
+
isActive: (item: Element) => boolean;
|
|
41
|
+
surface: () => "background";
|
|
42
|
+
spring: {
|
|
43
|
+
readonly type: "spring";
|
|
44
|
+
readonly visualDuration: 0.42;
|
|
45
|
+
readonly bounce: 0.16;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
menu: {
|
|
49
|
+
itemSelector: string;
|
|
50
|
+
containerSelector: string;
|
|
51
|
+
attributes: string[];
|
|
52
|
+
isActive: (item: Element) => boolean;
|
|
53
|
+
surface: () => "background";
|
|
54
|
+
spring: {
|
|
55
|
+
readonly type: "spring";
|
|
56
|
+
readonly visualDuration: 0.26;
|
|
57
|
+
readonly bounce: 0.12;
|
|
58
|
+
};
|
|
59
|
+
instantOnKeyboard: true;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export type GlidePresetName = keyof typeof GLIDE_PRESETS;
|
|
63
|
+
/** Marks the item whose own highlight is hidden while the travelling copy stands in for it. */
|
|
64
|
+
export declare const GLIDE_TARGET_ATTRIBUTE = "data-glide-target";
|
|
65
|
+
/** Marks items whose transitions, including pseudo-element ones, are suspended during a glide. */
|
|
66
|
+
export declare const GLIDE_FREEZE_ATTRIBUTE = "data-glide-freeze";
|
|
67
|
+
/** Observes the container and glides the highlight whenever the active item changes. */
|
|
68
|
+
export declare function attachGlideIndicator(container: HTMLElement, preset: GlidePreset): () => void;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glides an active-item indicator between items of a container, like a shared `layoutId`,
|
|
3
|
+
* without adding persistent markup: a transient copy of the target's highlight travels from the
|
|
4
|
+
* previous item and is removed once it lands, leaving the item's own styles in charge again.
|
|
5
|
+
*/
|
|
6
|
+
import { animate } from "motion/react";
|
|
7
|
+
import { GLIDE_CONTINUITY_MS } from "./tokens.js";
|
|
8
|
+
import { ARC_SPRING_MORPH, ARC_SPRING_SNAPPY } from "./arc-tokens.js";
|
|
9
|
+
export const GLIDE_PRESETS = {
|
|
10
|
+
tabs: {
|
|
11
|
+
itemSelector: "[data-slot=\"tabs-trigger\"]",
|
|
12
|
+
containerSelector: "[role=\"tablist\"]",
|
|
13
|
+
attributes: ["data-state"],
|
|
14
|
+
isActive: (item) => item.getAttribute("data-state") === "active",
|
|
15
|
+
surface: () => "background",
|
|
16
|
+
// Arc glides the tab highlight and the current page mark with its morph spring.
|
|
17
|
+
spring: ARC_SPRING_MORPH
|
|
18
|
+
},
|
|
19
|
+
pagination: {
|
|
20
|
+
itemSelector: "[data-slot=\"pagination-link\"]",
|
|
21
|
+
containerSelector: "[data-slot=\"pagination-content\"]",
|
|
22
|
+
attributes: ["aria-current"],
|
|
23
|
+
isActive: (item) => item.getAttribute("aria-current") === "page",
|
|
24
|
+
surface: () => "background",
|
|
25
|
+
spring: ARC_SPRING_MORPH
|
|
26
|
+
},
|
|
27
|
+
menu: {
|
|
28
|
+
itemSelector: "[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"]",
|
|
29
|
+
containerSelector: "[role=\"menu\"]",
|
|
30
|
+
attributes: ["data-highlighted"],
|
|
31
|
+
isActive: (item) => item.hasAttribute("data-highlighted"),
|
|
32
|
+
surface: () => "background",
|
|
33
|
+
spring: ARC_SPRING_SNAPPY,
|
|
34
|
+
instantOnKeyboard: true
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** Marks the item whose own highlight is hidden while the travelling copy stands in for it. */
|
|
38
|
+
export const GLIDE_TARGET_ATTRIBUTE = "data-glide-target";
|
|
39
|
+
/** Marks items whose transitions, including pseudo-element ones, are suspended during a glide. */
|
|
40
|
+
export const GLIDE_FREEZE_ATTRIBUTE = "data-glide-freeze";
|
|
41
|
+
/** Laid-out size of the border box, unaffected by any transform on the element or its ancestors. */
|
|
42
|
+
function layoutSize(element) {
|
|
43
|
+
const style = getComputedStyle(element);
|
|
44
|
+
const width = Number.parseFloat(style.width);
|
|
45
|
+
const height = Number.parseFloat(style.height);
|
|
46
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) {
|
|
47
|
+
return {
|
|
48
|
+
width: element.offsetWidth,
|
|
49
|
+
height: element.offsetHeight
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (style.boxSizing === "border-box") return {
|
|
53
|
+
width,
|
|
54
|
+
height
|
|
55
|
+
};
|
|
56
|
+
const sum = (...values) => values.reduce((total, value) => total + (Number.parseFloat(value) || 0), 0);
|
|
57
|
+
return {
|
|
58
|
+
width: width + sum(style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth),
|
|
59
|
+
height: height + sum(style.paddingTop, style.paddingBottom, style.borderTopWidth, style.borderBottomWidth)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Converts a viewport rectangle into the container's own scrolling coordinate space. A container
|
|
64
|
+
* still scaling in (a menu or listbox entrance) paints everything inside it smaller, so painted
|
|
65
|
+
* distances are divided by that scale to land where absolute positioning places the copy.
|
|
66
|
+
*/
|
|
67
|
+
function toContainerBox(container, rect) {
|
|
68
|
+
const origin = container.getBoundingClientRect();
|
|
69
|
+
const layout = layoutSize(container);
|
|
70
|
+
const scaleX = layout.width > 0 && origin.width > 0 ? origin.width / layout.width : 1;
|
|
71
|
+
const scaleY = layout.height > 0 && origin.height > 0 ? origin.height / layout.height : 1;
|
|
72
|
+
return {
|
|
73
|
+
left: (rect.left - origin.left) / scaleX - container.clientLeft + container.scrollLeft,
|
|
74
|
+
top: (rect.top - origin.top) / scaleY - container.clientTop + container.scrollTop,
|
|
75
|
+
width: rect.width / scaleX,
|
|
76
|
+
height: rect.height / scaleY
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Scale and translation an item's own running entrance adds, read from its computed `matrix()`. */
|
|
80
|
+
function inFlightTransform(item) {
|
|
81
|
+
const style = getComputedStyle(item);
|
|
82
|
+
const values = /^matrix\(([^)]+)\)$/.exec(style.transform);
|
|
83
|
+
const [originX = 0, originY = 0] = style.transformOrigin.split(" ").map(Number.parseFloat);
|
|
84
|
+
if (!values) return {
|
|
85
|
+
scaleX: 1,
|
|
86
|
+
scaleY: 1,
|
|
87
|
+
x: 0,
|
|
88
|
+
y: 0,
|
|
89
|
+
originX,
|
|
90
|
+
originY
|
|
91
|
+
};
|
|
92
|
+
const parts = values[1].split(",").map(Number.parseFloat);
|
|
93
|
+
return {
|
|
94
|
+
scaleX: parts[0] || 1,
|
|
95
|
+
scaleY: parts[3] || 1,
|
|
96
|
+
x: parts[4] ?? 0,
|
|
97
|
+
y: parts[5] ?? 0,
|
|
98
|
+
originX,
|
|
99
|
+
originY
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Measures the highlight in the container's coordinates: the item box, or its positioned `::after`
|
|
104
|
+
* bar for line variants. An item still entering (Select options settle from a slight scale) is
|
|
105
|
+
* measured where it will rest, so the highlight neither lands undersized nor jumps when it ends.
|
|
106
|
+
*/
|
|
107
|
+
function highlightBox(container, item, surface) {
|
|
108
|
+
const painted = toContainerBox(container, item.getBoundingClientRect());
|
|
109
|
+
const motion = inFlightTransform(item);
|
|
110
|
+
// The entrance scales around the transform origin, so the resting corner sits that far back.
|
|
111
|
+
const rect = {
|
|
112
|
+
left: painted.left - motion.x - motion.originX * (1 - motion.scaleX),
|
|
113
|
+
top: painted.top - motion.y - motion.originY * (1 - motion.scaleY),
|
|
114
|
+
width: painted.width / motion.scaleX,
|
|
115
|
+
height: painted.height / motion.scaleY
|
|
116
|
+
};
|
|
117
|
+
if (surface === "background") return rect;
|
|
118
|
+
const pseudo = getComputedStyle(item, "::after");
|
|
119
|
+
return {
|
|
120
|
+
left: rect.left + item.clientLeft + (parseFloat(pseudo.left) || 0),
|
|
121
|
+
top: rect.top + item.clientTop + (parseFloat(pseudo.top) || 0),
|
|
122
|
+
width: parseFloat(pseudo.width) || rect.width,
|
|
123
|
+
height: parseFloat(pseudo.height) || 0
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Copies only the paint that identifies the highlight, never layout or content. */
|
|
127
|
+
function highlightPaint(item, surface) {
|
|
128
|
+
const style = getComputedStyle(item, surface === "after" ? "::after" : null);
|
|
129
|
+
return {
|
|
130
|
+
backgroundColor: style.backgroundColor,
|
|
131
|
+
borderRadius: style.borderRadius,
|
|
132
|
+
boxShadow: style.boxShadow,
|
|
133
|
+
borderStyle: style.borderStyle,
|
|
134
|
+
borderWidth: style.borderWidth,
|
|
135
|
+
borderColor: style.borderColor,
|
|
136
|
+
boxSizing: "border-box"
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** Tracks overlapping freezes so the caller-owned inline transition is restored exactly once. */
|
|
140
|
+
const frozenItems = new WeakMap();
|
|
141
|
+
/**
|
|
142
|
+
* Suppresses CSS transitions for one item, so state changes paint instantly; the returned
|
|
143
|
+
* release restores them after two painted frames. Overlapping freezes are reference-counted.
|
|
144
|
+
*/
|
|
145
|
+
function freezeTransitions(item) {
|
|
146
|
+
const frozen = frozenItems.get(item) ?? {
|
|
147
|
+
transition: item.style.transition,
|
|
148
|
+
holds: 0
|
|
149
|
+
};
|
|
150
|
+
frozen.holds += 1;
|
|
151
|
+
frozenItems.set(item, frozen);
|
|
152
|
+
item.style.transition = "none";
|
|
153
|
+
item.setAttribute(GLIDE_FREEZE_ATTRIBUTE, "");
|
|
154
|
+
let released = false;
|
|
155
|
+
return () => {
|
|
156
|
+
if (released) return;
|
|
157
|
+
released = true;
|
|
158
|
+
requestAnimationFrame(() => {
|
|
159
|
+
requestAnimationFrame(() => {
|
|
160
|
+
frozen.holds -= 1;
|
|
161
|
+
if (frozen.holds > 0) return;
|
|
162
|
+
frozenItems.delete(item);
|
|
163
|
+
item.style.transition = frozen.transition;
|
|
164
|
+
item.removeAttribute(GLIDE_FREEZE_ATTRIBUTE);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** Observes the container and glides the highlight whenever the active item changes. */
|
|
170
|
+
export function attachGlideIndicator(container, preset) {
|
|
171
|
+
const items = () => Array.from(container.querySelectorAll(preset.itemSelector)).filter((item) => item.parentElement?.closest(preset.containerSelector) === container);
|
|
172
|
+
let lastActive = items().find(preset.isActive) ?? null;
|
|
173
|
+
let lastActiveSeenAt = Number.NEGATIVE_INFINITY;
|
|
174
|
+
let overlay = null;
|
|
175
|
+
let animation = null;
|
|
176
|
+
let releaseTarget = null;
|
|
177
|
+
const containerStyle = {
|
|
178
|
+
position: container.style.position,
|
|
179
|
+
isolation: container.style.isolation
|
|
180
|
+
};
|
|
181
|
+
// The last input decides whether a highlight change was driven by the pointer or the keyboard.
|
|
182
|
+
// Keyboard focus may live outside the container (a combobox input), so both are read from the
|
|
183
|
+
// document; the pointer only counts while it moves over this container.
|
|
184
|
+
let isPointerDriven = false;
|
|
185
|
+
const onPointerMove = () => {
|
|
186
|
+
isPointerDriven = true;
|
|
187
|
+
};
|
|
188
|
+
const onKeyDown = () => {
|
|
189
|
+
isPointerDriven = false;
|
|
190
|
+
};
|
|
191
|
+
if (preset.instantOnKeyboard) {
|
|
192
|
+
container.addEventListener("pointermove", onPointerMove);
|
|
193
|
+
container.ownerDocument.addEventListener("keydown", onKeyDown, true);
|
|
194
|
+
}
|
|
195
|
+
/** Puts the item's own highlight back and removes the travelling copy. */
|
|
196
|
+
function settle() {
|
|
197
|
+
animation?.cancel();
|
|
198
|
+
animation = null;
|
|
199
|
+
overlay?.remove();
|
|
200
|
+
overlay = null;
|
|
201
|
+
releaseTarget?.();
|
|
202
|
+
releaseTarget = null;
|
|
203
|
+
container.style.position = containerStyle.position;
|
|
204
|
+
container.style.isolation = containerStyle.isolation;
|
|
205
|
+
}
|
|
206
|
+
/** Hides the frozen target's highlight so the copy is the only one visible. */
|
|
207
|
+
function hideTarget(item, surface, thaw) {
|
|
208
|
+
item.setAttribute(GLIDE_TARGET_ATTRIBUTE, "");
|
|
209
|
+
const inline = {
|
|
210
|
+
backgroundColor: item.style.getPropertyValue("background-color"),
|
|
211
|
+
backgroundPriority: item.style.getPropertyPriority("background-color"),
|
|
212
|
+
boxShadow: item.style.getPropertyValue("box-shadow"),
|
|
213
|
+
boxShadowPriority: item.style.getPropertyPriority("box-shadow"),
|
|
214
|
+
borderColor: item.style.getPropertyValue("border-color"),
|
|
215
|
+
borderPriority: item.style.getPropertyPriority("border-color")
|
|
216
|
+
};
|
|
217
|
+
if (surface === "background") {
|
|
218
|
+
item.style.setProperty("background-color", "transparent", "important");
|
|
219
|
+
item.style.setProperty("box-shadow", "none", "important");
|
|
220
|
+
item.style.setProperty("border-color", "transparent", "important");
|
|
221
|
+
}
|
|
222
|
+
return () => {
|
|
223
|
+
item.style.setProperty("background-color", inline.backgroundColor, inline.backgroundPriority);
|
|
224
|
+
item.style.setProperty("box-shadow", inline.boxShadow, inline.boxShadowPriority);
|
|
225
|
+
item.style.setProperty("border-color", inline.borderColor, inline.borderPriority);
|
|
226
|
+
// Transitions stay frozen until the restored highlight has painted in place.
|
|
227
|
+
item.removeAttribute(GLIDE_TARGET_ATTRIBUTE);
|
|
228
|
+
thaw();
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/** Starts, or redirects, the glide from the previous highlight to the new active item. */
|
|
232
|
+
function glide(from, to) {
|
|
233
|
+
const surface = preset.surface(container);
|
|
234
|
+
const start = overlay ? toContainerBox(container, overlay.getBoundingClientRect()) : highlightBox(container, from, surface);
|
|
235
|
+
settle();
|
|
236
|
+
// The previous item drops its highlight instantly: the copy is what leaves it.
|
|
237
|
+
freezeTransitions(from)();
|
|
238
|
+
// Read the target's settled paint before any transition has a chance to start.
|
|
239
|
+
const thawTarget = freezeTransitions(to);
|
|
240
|
+
const destination = highlightBox(container, to, surface);
|
|
241
|
+
const paint = highlightPaint(to, surface);
|
|
242
|
+
if (destination.width === 0 || destination.height === 0) {
|
|
243
|
+
thawTarget();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (getComputedStyle(container).position === "static") {
|
|
247
|
+
container.style.position = "relative";
|
|
248
|
+
}
|
|
249
|
+
// Negative z-index keeps the copy above the container background and below item content.
|
|
250
|
+
container.style.isolation = "isolate";
|
|
251
|
+
overlay = document.createElement("span");
|
|
252
|
+
overlay.setAttribute("aria-hidden", "true");
|
|
253
|
+
overlay.setAttribute("data-glide-indicator", "");
|
|
254
|
+
Object.assign(overlay.style, paint, {
|
|
255
|
+
position: "absolute",
|
|
256
|
+
pointerEvents: "none",
|
|
257
|
+
zIndex: "-1",
|
|
258
|
+
margin: "0"
|
|
259
|
+
});
|
|
260
|
+
container.prepend(overlay);
|
|
261
|
+
releaseTarget = hideTarget(to, surface, thawTarget);
|
|
262
|
+
animation = animate(overlay, {
|
|
263
|
+
left: [`${start.left}px`, `${destination.left}px`],
|
|
264
|
+
top: [`${start.top}px`, `${destination.top}px`],
|
|
265
|
+
width: [`${start.width}px`, `${destination.width}px`],
|
|
266
|
+
height: [`${start.height}px`, `${destination.height}px`]
|
|
267
|
+
}, preset.spring);
|
|
268
|
+
const current = animation;
|
|
269
|
+
void current.then(() => {
|
|
270
|
+
if (animation === current) settle();
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
const observer = new MutationObserver(() => {
|
|
274
|
+
// Items can be remounted (a button wrapped in a tooltip trigger after hydration); the
|
|
275
|
+
// highlight then belongs to the item that replaced the detached one.
|
|
276
|
+
if (lastActive && !lastActive.isConnected) {
|
|
277
|
+
lastActive = items().find(preset.isActive) ?? null;
|
|
278
|
+
lastActiveSeenAt = Number.NEGATIVE_INFINITY;
|
|
279
|
+
}
|
|
280
|
+
const active = items().find(preset.isActive) ?? null;
|
|
281
|
+
const now = performance.now();
|
|
282
|
+
if (active && active === lastActive) return;
|
|
283
|
+
if (!active) {
|
|
284
|
+
if (lastActive && lastActiveSeenAt === Number.NEGATIVE_INFINITY) {
|
|
285
|
+
lastActiveSeenAt = now;
|
|
286
|
+
}
|
|
287
|
+
settle();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const previous = lastActive;
|
|
291
|
+
const isContinuous = previous !== null && previous !== active && previous.isConnected && !preset.isActive(previous) && (lastActiveSeenAt === Number.NEGATIVE_INFINITY || now - lastActiveSeenAt <= GLIDE_CONTINUITY_MS);
|
|
292
|
+
lastActive = active;
|
|
293
|
+
lastActiveSeenAt = Number.NEGATIVE_INFINITY;
|
|
294
|
+
if (isContinuous && !(preset.instantOnKeyboard && !isPointerDriven)) glide(previous, active);
|
|
295
|
+
else settle();
|
|
296
|
+
});
|
|
297
|
+
observer.observe(container, {
|
|
298
|
+
subtree: true,
|
|
299
|
+
childList: true,
|
|
300
|
+
attributes: true,
|
|
301
|
+
attributeFilter: preset.attributes
|
|
302
|
+
});
|
|
303
|
+
return () => {
|
|
304
|
+
observer.disconnect();
|
|
305
|
+
container.removeEventListener("pointermove", onPointerMove);
|
|
306
|
+
container.ownerDocument.removeEventListener("keydown", onKeyDown, true);
|
|
307
|
+
settle();
|
|
308
|
+
};
|
|
309
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Adds a gliding active-item indicator to the original container, without DOM wrappers. */
|
|
2
|
+
import { type ComponentProps, type ReactElement } from "react";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { type GlidePresetName } from "./glide-indicator.js";
|
|
5
|
+
/** Composes refs through Radix Slot and glides the preset's highlight between its items. */
|
|
6
|
+
export declare function GlideSlot({ children, preset, ref, ...props }: Omit<ComponentProps<typeof Slot.Root>, "children"> & {
|
|
7
|
+
children: ReactElement;
|
|
8
|
+
preset: GlidePresetName;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
|
+
/** Adds a gliding active-item indicator to the original container, without DOM wrappers. */
|
|
4
|
+
import { useLayoutEffect } from "react";
|
|
5
|
+
import { Slot } from "radix-ui";
|
|
6
|
+
import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
|
|
7
|
+
import { attachGlideIndicator, GLIDE_PRESETS } from "./glide-indicator.js";
|
|
8
|
+
import { useAttachedElement } from "./use-attached-element.js";
|
|
9
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
|
+
/** Composes refs through Radix Slot and glides the preset's highlight between its items. */
|
|
11
|
+
export function GlideSlot(t0) {
|
|
12
|
+
const $ = _c(14);
|
|
13
|
+
let children;
|
|
14
|
+
let preset;
|
|
15
|
+
let props;
|
|
16
|
+
let ref;
|
|
17
|
+
if ($[0] !== t0) {
|
|
18
|
+
({children, preset, ref, ...props} = t0);
|
|
19
|
+
$[0] = t0;
|
|
20
|
+
$[1] = children;
|
|
21
|
+
$[2] = preset;
|
|
22
|
+
$[3] = props;
|
|
23
|
+
$[4] = ref;
|
|
24
|
+
} else {
|
|
25
|
+
children = $[1];
|
|
26
|
+
preset = $[2];
|
|
27
|
+
props = $[3];
|
|
28
|
+
ref = $[4];
|
|
29
|
+
}
|
|
30
|
+
const [element, attach] = useAttachedElement(ref);
|
|
31
|
+
const reduceMotion = usePrefersReducedMotion();
|
|
32
|
+
let t1;
|
|
33
|
+
let t2;
|
|
34
|
+
if ($[5] !== element || $[6] !== preset || $[7] !== reduceMotion) {
|
|
35
|
+
t1 = () => {
|
|
36
|
+
if (!element || reduceMotion) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
return attachGlideIndicator(element, GLIDE_PRESETS[preset]);
|
|
40
|
+
};
|
|
41
|
+
t2 = [
|
|
42
|
+
element,
|
|
43
|
+
preset,
|
|
44
|
+
reduceMotion
|
|
45
|
+
];
|
|
46
|
+
$[5] = element;
|
|
47
|
+
$[6] = preset;
|
|
48
|
+
$[7] = reduceMotion;
|
|
49
|
+
$[8] = t1;
|
|
50
|
+
$[9] = t2;
|
|
51
|
+
} else {
|
|
52
|
+
t1 = $[8];
|
|
53
|
+
t2 = $[9];
|
|
54
|
+
}
|
|
55
|
+
useLayoutEffect(t1, t2);
|
|
56
|
+
let t3;
|
|
57
|
+
if ($[10] !== attach || $[11] !== children || $[12] !== props) {
|
|
58
|
+
t3 = /* @__PURE__ */ _jsx(Slot.Root, {
|
|
59
|
+
...props,
|
|
60
|
+
ref: attach,
|
|
61
|
+
children
|
|
62
|
+
});
|
|
63
|
+
$[10] = attach;
|
|
64
|
+
$[11] = children;
|
|
65
|
+
$[12] = props;
|
|
66
|
+
$[13] = t3;
|
|
67
|
+
} else {
|
|
68
|
+
t3 = $[13];
|
|
69
|
+
}
|
|
70
|
+
return t3;
|
|
71
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animates the original primitive node with Motion, without adding DOM wrappers. Every kind plays Arc's motion
|
|
3
|
+
* (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md) for the component it serves.
|
|
4
|
+
*/
|
|
5
|
+
import { type ReactElement, type ComponentProps } from "react";
|
|
6
|
+
import { Slot } from "radix-ui";
|
|
7
|
+
import { type MotionKind } from "./tokens.js";
|
|
8
|
+
/** Composes refs through Radix Slot and delegates entry, exit and state playback to Motion. */
|
|
9
|
+
export declare function MotionSlot({ children, kind, ref, ...props }: Omit<ComponentProps<typeof Slot.Root>, "children"> & {
|
|
10
|
+
children: ReactElement;
|
|
11
|
+
kind: MotionKind;
|
|
12
|
+
}): import("react").JSX.Element;
|