@mova-ui/react 0.4.7 → 0.4.8
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/dist/index.js +2555 -449
- package/dist/styles.css +1 -1
- package/dist/ui/cards/calendar-day-card.d.ts +6 -0
- package/dist/ui/cards/day-trading-order-ticket.d.ts +4 -2
- package/dist/ui/cards/imessage-chat.d.ts +3 -1
- package/dist/ui/cards/liquid-glass-sheet.d.ts +3 -1
- package/dist/ui/cards/voice-assistant-card.d.ts +3 -1
- package/package.json +3 -2
- package/registry/1.json +1 -1
- package/registry/10.json +1 -1
- package/registry/11.json +1 -1
- package/registry/12.json +1 -1
- package/registry/13.json +1 -1
- package/registry/14.json +1 -1
- package/registry/15.json +1 -1
- package/registry/16.json +1 -1
- package/registry/17.json +1 -1
- package/registry/18.json +1 -1
- package/registry/19.json +1 -1
- package/registry/2.json +1 -1
- package/registry/20.json +1 -1
- package/registry/21.json +1 -1
- package/registry/22.json +1 -1
- package/registry/23.json +1 -1
- package/registry/24.json +1 -1
- package/registry/25.json +1 -1
- package/registry/26.json +1 -1
- package/registry/27.json +1 -1
- package/registry/28.json +1 -1
- package/registry/29.json +1 -1
- package/registry/3.json +1 -1
- package/registry/30.json +1 -1
- package/registry/31.json +1 -1
- package/registry/32.json +1 -1
- package/registry/33.json +1 -1
- package/registry/34.json +1 -1
- package/registry/35.json +1 -1
- package/registry/36.json +1 -1
- package/registry/37.json +1 -1
- package/registry/4.json +1 -1
- package/registry/5.json +1 -1
- package/registry/6.json +1 -1
- package/registry/7.json +1 -1
- package/registry/8.json +1 -1
- package/registry/9.json +1 -1
- package/registry/ab-segmented-tabs.json +1 -1
- package/registry/accordion-blind.json +1 -1
- package/registry/accordion-loader.json +1 -1
- package/registry/ai-approval-card.json +1 -1
- package/registry/ai-code-block.json +1 -1
- package/registry/ai-context-meter.json +1 -1
- package/registry/ai-fine-tune-card.json +1 -1
- package/registry/ai-prompt-bar.json +1 -1
- package/registry/ai-sidebar-nav.json +1 -1
- package/registry/ai-sources.json +1 -1
- package/registry/ai-suggestions.json +1 -1
- package/registry/ai-task-list.json +1 -1
- package/registry/ai-tool-call.json +1 -1
- package/registry/analyzing-image.json +1 -1
- package/registry/animated-sidebar.json +1 -1
- package/registry/animated-tags.json +1 -1
- package/registry/app-icon-load.json +1 -1
- package/registry/apple-breathe.json +1 -1
- package/registry/apple-equalizer.json +1 -1
- package/registry/apple-icon-morph.json +1 -1
- package/registry/apple-pulse-dots.json +1 -1
- package/registry/apple-scale-pulse.json +1 -1
- package/registry/apple-sound-wave.json +1 -1
- package/registry/apple-text-reveal.json +1 -1
- package/registry/apple-unlock.json +1 -1
- package/registry/arc-tracer.json +1 -1
- package/registry/balance-bar-chart-card.json +3 -5
- package/registry/bar-cascade.json +1 -1
- package/registry/bar-sweep.json +1 -1
- package/registry/blur-text.json +1 -1
- package/registry/blur-up-char.json +1 -1
- package/registry/blur-up-word.json +1 -1
- package/registry/bobbing-dots.json +1 -1
- package/registry/bookmark-corner-peel.json +1 -1
- package/registry/bookmark-save-pill.json +1 -1
- package/registry/bookmark-toggle.json +1 -1
- package/registry/border-trail-loading.json +1 -1
- package/registry/bounce-dots.json +1 -1
- package/registry/bounce-in-char.json +1 -1
- package/registry/bouncing-bars.json +1 -1
- package/registry/bouncing-dots.json +1 -1
- package/registry/bouncing-lines.json +1 -1
- package/registry/bouncing-square.json +1 -1
- package/registry/breathe-ring.json +1 -1
- package/registry/breathing-glow.json +1 -1
- package/registry/breathing-square.json +1 -1
- package/registry/btn-1.json +1 -1
- package/registry/btn-10.json +1 -1
- package/registry/btn-11.json +1 -1
- package/registry/btn-12.json +1 -1
- package/registry/btn-13.json +1 -1
- package/registry/btn-14.json +1 -1
- package/registry/btn-15.json +1 -1
- package/registry/btn-16.json +1 -1
- package/registry/btn-17.json +1 -1
- package/registry/btn-18.json +1 -1
- package/registry/btn-19.json +1 -1
- package/registry/btn-2.json +1 -1
- package/registry/btn-20.json +1 -1
- package/registry/btn-21.json +1 -1
- package/registry/btn-22.json +1 -1
- package/registry/btn-23.json +1 -1
- package/registry/btn-24.json +1 -1
- package/registry/btn-25.json +1 -1
- package/registry/btn-26.json +1 -1
- package/registry/btn-27.json +1 -1
- package/registry/btn-28.json +1 -1
- package/registry/btn-29.json +1 -1
- package/registry/btn-3.json +1 -1
- package/registry/btn-30.json +1 -1
- package/registry/btn-31.json +1 -1
- package/registry/btn-32.json +1 -1
- package/registry/btn-33.json +1 -1
- package/registry/btn-34.json +1 -1
- package/registry/btn-35.json +1 -1
- package/registry/btn-36.json +1 -1
- package/registry/btn-37.json +1 -1
- package/registry/btn-4.json +1 -1
- package/registry/btn-5.json +1 -1
- package/registry/btn-6.json +1 -1
- package/registry/btn-7.json +1 -1
- package/registry/btn-8.json +1 -1
- package/registry/btn-9.json +1 -1
- package/registry/button-slide-arrow.json +1 -1
- package/registry/cacheable-bandwidth-cost.json +1 -1
- package/registry/calendar-day-card.json +4 -5
- package/registry/card-arc-5.json +1 -1
- package/registry/card-arc-7.json +1 -1
- package/registry/card-carousel-mono.json +1 -1
- package/registry/card-carousel.json +1 -1
- package/registry/card-cascade-stagger.json +1 -1
- package/registry/card-corner-fan.json +1 -1
- package/registry/card-cover-flow-mono.json +1 -1
- package/registry/card-cover-flow.json +1 -1
- package/registry/card-deck-cascade.json +1 -1
- package/registry/card-glance-preview.json +1 -1
- package/registry/card-hover.json +1 -1
- package/registry/card-linear-spread.json +1 -1
- package/registry/card-long-arc-5.json +1 -1
- package/registry/card-scatter-spread.json +1 -1
- package/registry/card-stack-peel.json +1 -1
- package/registry/card-stamp-arc.json +1 -1
- package/registry/card-time-machine-mono.json +1 -1
- package/registry/card-time-machine.json +1 -1
- package/registry/card-wheel-fan.json +1 -1
- package/registry/category-select.json +1 -1
- package/registry/character-stagger.json +1 -1
- package/registry/checkbox-draw.json +1 -1
- package/registry/checkmark-draw.json +1 -1
- package/registry/circle-toggle.json +1 -1
- package/registry/circuit-trace-draw.json +1 -1
- package/registry/circular-bars.json +1 -1
- package/registry/circular-create-button.json +1 -1
- package/registry/classic-spinner.json +1 -1
- package/registry/classic-toggle.json +1 -1
- package/registry/clock-spinner.json +1 -1
- package/registry/comet-spinner.json +1 -1
- package/registry/compass-needle-deflect.json +1 -1
- package/registry/concentric-pulse.json +1 -1
- package/registry/concentric-ring.json +1 -1
- package/registry/concentric-squares.json +1 -1
- package/registry/context-menu.json +1 -1
- package/registry/conveyor-loop.json +1 -1
- package/registry/credit-score-barcode-meter.json +1 -1
- package/registry/cross-spinner.json +1 -1
- package/registry/cube-flip-spring.json +1 -1
- package/registry/cursor-trail.json +1 -1
- package/registry/dash-ring.json +1 -1
- package/registry/dashed-spiral.json +1 -1
- package/registry/date-position-selector.json +1 -1
- package/registry/day-trading-order-ticket.json +3 -5
- package/registry/dia-text-reveal.json +1 -1
- package/registry/diamond-grid.json +1 -1
- package/registry/diamond-rotate-spring.json +1 -1
- package/registry/dislike-toggle.json +1 -1
- package/registry/dither-book.json +1 -1
- package/registry/domino-cascade.json +1 -1
- package/registry/dot-spinner.json +1 -1
- package/registry/dots-ring.json +1 -1
- package/registry/double-bounce-toggle.json +1 -1
- package/registry/double-ring.json +1 -1
- package/registry/download-icons.json +1 -1
- package/registry/drop-dot.json +1 -1
- package/registry/drop-in-char.json +1 -1
- package/registry/droplet-squish.json +1 -1
- package/registry/dual-arc.json +1 -1
- package/registry/dual-magnet-dipole.json +1 -1
- package/registry/dynamic-island.json +1 -1
- package/registry/elastic-bars.json +1 -1
- package/registry/elastic-square.json +1 -1
- package/registry/elastic-tag-snap.json +1 -1
- package/registry/error-shake.json +1 -1
- package/registry/expanding-cross.json +1 -1
- package/registry/expanding-icon-tabs.json +1 -1
- package/registry/face-id-scan.json +1 -1
- package/registry/fade-arc.json +1 -1
- package/registry/fade-dots.json +1 -1
- package/registry/fade-down.json +1 -1
- package/registry/fade-in-char.json +1 -1
- package/registry/fade-in-text.json +1 -1
- package/registry/fade-in-word.json +1 -1
- package/registry/fade-in.json +1 -1
- package/registry/fade-up.json +1 -1
- package/registry/file-upload-dropzone.json +1 -1
- package/registry/filter-tag-pill.json +1 -1
- package/registry/flip-square.json +1 -1
- package/registry/flip-x-char.json +1 -1
- package/registry/flip-y-char.json +1 -1
- package/registry/float-char.json +1 -1
- package/registry/float-word.json +1 -1
- package/registry/floating-diamonds.json +1 -1
- package/registry/floating-label-input.json +1 -1
- package/registry/fluid-bars.json +1 -1
- package/registry/fluid-diamond.json +1 -1
- package/registry/fluid-dot-orbit.json +1 -1
- package/registry/fluid-skeleton.json +1 -1
- package/registry/focus-blur.json +1 -1
- package/registry/form-submit-button.json +1 -1
- package/registry/french-doors-3d.json +1 -1
- package/registry/gear-tooth-step.json +1 -1
- package/registry/gears.json +1 -1
- package/registry/gelatin-wobble.json +1 -1
- package/registry/geometric-iris-shutter.json +1 -1
- package/registry/glassmorphic-card.json +1 -1
- package/registry/glow-button.json +1 -1
- package/registry/glow-text.json +1 -1
- package/registry/gooey-popover.json +1 -1
- package/registry/gradient-arc.json +1 -1
- package/registry/gradient-shimmer.json +1 -1
- package/registry/grid-dots.json +1 -1
- package/registry/haptic-ring.json +1 -1
- package/registry/heartbeat.json +1 -1
- package/registry/hex-lattice-draw.json +1 -1
- package/registry/hexagon-spinner.json +1 -1
- package/registry/hourglass.json +1 -1
- package/registry/hover-lift-char.json +1 -1
- package/registry/hover-lift-word.json +1 -1
- package/registry/hover-link-card.json +1 -1
- package/registry/hover-scale-char.json +1 -1
- package/registry/hover-scale-word.json +1 -1
- package/registry/imessage-chat.json +2 -2
- package/registry/inertia-skid-stop.json +1 -1
- package/registry/infinity-path.json +1 -1
- package/registry/input-focus-glow.json +1 -1
- package/registry/inset-action-button.json +1 -1
- package/registry/inset-button.json +1 -1
- package/registry/intersecting-rings.json +1 -1
- package/registry/ios-spinner.json +1 -1
- package/registry/kinetic-metronome-tick.json +1 -1
- package/registry/kinetic-tension-capsule.json +1 -1
- package/registry/light-dark-morph.json +1 -1
- package/registry/like-toggle.json +1 -1
- package/registry/line-spinner.json +1 -1
- package/registry/liquid-dots.json +1 -1
- package/registry/liquid-glass-sheet.json +3 -5
- package/registry/mac-terminal.json +1 -1
- package/registry/magnetic-button.json +1 -1
- package/registry/magnetic-disks.json +1 -1
- package/registry/magnetic-dots.json +1 -1
- package/registry/magnetic-slide-btn.json +1 -1
- package/registry/manifest.json +658 -665
- package/registry/matrix-grid-loader.json +1 -1
- package/registry/minimal-triangle.json +1 -1
- package/registry/modular-tile-snap.json +1 -1
- package/registry/mono-activity-blue.json +1 -1
- package/registry/mono-activity-green.json +1 -1
- package/registry/mono-activity-purple.json +1 -1
- package/registry/mono-heatmap.json +1 -1
- package/registry/mono-rounded-area.json +1 -1
- package/registry/mono-rounded-bar.json +1 -1
- package/registry/mono-rounded-bubble.json +1 -1
- package/registry/mono-rounded-bullet.json +1 -1
- package/registry/mono-rounded-candlestick.json +1 -1
- package/registry/mono-rounded-composed.json +1 -1
- package/registry/mono-rounded-donut.json +1 -1
- package/registry/mono-rounded-funnel.json +1 -1
- package/registry/mono-rounded-gauge-arc.json +1 -1
- package/registry/mono-rounded-heatmap.json +1 -1
- package/registry/mono-rounded-kpi.json +1 -1
- package/registry/mono-rounded-line.json +1 -1
- package/registry/mono-rounded-meter.json +1 -1
- package/registry/mono-rounded-polar.json +1 -1
- package/registry/mono-rounded-pyramid.json +1 -1
- package/registry/mono-rounded-radar.json +1 -1
- package/registry/mono-rounded-radial-gauge.json +1 -1
- package/registry/mono-rounded-radial-group.json +1 -1
- package/registry/mono-rounded-range.json +1 -1
- package/registry/mono-rounded-sankey.json +1 -1
- package/registry/mono-rounded-scatter.json +1 -1
- package/registry/mono-rounded-sparkline.json +1 -1
- package/registry/mono-rounded-stacked-bar.json +1 -1
- package/registry/mono-rounded-step.json +1 -1
- package/registry/mono-rounded-stream.json +1 -1
- package/registry/mono-rounded-treemap.json +1 -1
- package/registry/mono-rounded-waterfall.json +1 -1
- package/registry/mono-stock.json +1 -1
- package/registry/morph-action-pill.json +1 -1
- package/registry/morph-dot-ring.json +1 -1
- package/registry/morph-loader.json +1 -1
- package/registry/morph-toggle.json +1 -1
- package/registry/morphing-bars.json +1 -1
- package/registry/morphing-infinity.json +1 -1
- package/registry/morphing-ring.json +1 -1
- package/registry/morphing-shape.json +1 -1
- package/registry/mouse-follow.json +1 -1
- package/registry/multi-select-chips.json +1 -1
- package/registry/multi-tab-bar.json +1 -1
- package/registry/neon-sign-draw.json +1 -1
- package/registry/nested-orbital-gimbal.json +1 -1
- package/registry/network-telemetry-matrix.json +1 -1
- package/registry/newtons-cradle.json +1 -1
- package/registry/noise-decibel-level.json +1 -1
- package/registry/obsidian-liquid-wave.json +1 -1
- package/registry/offset-rings.json +1 -1
- package/registry/orbiting-circles.json +1 -1
- package/registry/orbiting-dot.json +1 -1
- package/registry/origami-envelope-unfold.json +1 -1
- package/registry/origami-shape.json +1 -1
- package/registry/otp-input.json +1 -1
- package/registry/overview-bar-scrubber-card.json +1 -1
- package/registry/page-transition.json +1 -1
- package/registry/page-turn-curl.json +1 -1
- package/registry/password-toggle.json +1 -1
- package/registry/pendulum-bubble-level.json +1 -1
- package/registry/pendulum.json +1 -1
- package/registry/perspective-flip-stage.json +1 -1
- package/registry/perspective-flip.json +1 -1
- package/registry/perspective-layout-switcher.json +1 -1
- package/registry/physics-dock.json +1 -1
- package/registry/pill-tabs.json +1 -1
- package/registry/plus-minus-toggle.json +1 -1
- package/registry/presets.json +1 -1
- package/registry/prism-block-stack.json +1 -1
- package/registry/progress-indicator-piano.json +1 -1
- package/registry/progress-indicator.json +1 -1
- package/registry/progress-stepper.json +1 -1
- package/registry/pulsating-dots.json +1 -1
- package/registry/pulse-char.json +1 -1
- package/registry/pulse-dot.json +1 -1
- package/registry/pulse-dots.json +1 -1
- package/registry/pulse-square.json +1 -1
- package/registry/pulse-word.json +1 -1
- package/registry/pulse.json +1 -1
- package/registry/pumping-heart.json +1 -1
- package/registry/pyramid-block-build.json +1 -1
- package/registry/radar-sweep.json +1 -1
- package/registry/radial-iris-mask.json +1 -1
- package/registry/radial-spinner.json +1 -1
- package/registry/radio-scale.json +1 -1
- package/registry/range-slider.json +1 -1
- package/registry/receipt-tape-print.json +1 -1
- package/registry/rectangle-toggle.json +1 -1
- package/registry/repost-toggle.json +1 -1
- package/registry/reveal-text.json +1 -1
- package/registry/ribbon-banner-slide.json +1 -1
- package/registry/ring-sweep.json +1 -1
- package/registry/ripple-effect.json +1 -1
- package/registry/rise-up-word.json +1 -1
- package/registry/roller-blind-drop.json +1 -1
- package/registry/rolling-tumble.json +1 -1
- package/registry/rotate-in-char.json +1 -1
- package/registry/rotating-cross.json +1 -1
- package/registry/rotating-louvers.json +1 -1
- package/registry/rotating-triangle.json +1 -1
- package/registry/rudder-issue-board.json +1 -1
- package/registry/sales-analytics-dual-bars.json +1 -1
- package/registry/sales-overview-radial-dashboard.json +1 -1
- package/registry/sales-target-segmented-arc.json +1 -1
- package/registry/scale-in-char.json +1 -1
- package/registry/scale-in-text.json +1 -1
- package/registry/scale-in-word.json +1 -1
- package/registry/scale-in.json +1 -1
- package/registry/scramble-text.json +1 -1
- package/registry/scroll-canvas-unroll.json +1 -1
- package/registry/scroll-reveal.json +1 -1
- package/registry/search-expand.json +1 -1
- package/registry/segmented-arc-meter.json +1 -1
- package/registry/segmented-link-stretch.json +1 -1
- package/registry/segmented-step-bar.json +1 -1
- package/registry/segmented-stepper-dots.json +1 -1
- package/registry/select-dropdown.json +1 -1
- package/registry/server-performance-step-bars.json +1 -1
- package/registry/shape-shift-grid.json +1 -1
- package/registry/shimmer-line.json +1 -1
- package/registry/shimmer-text.json +1 -1
- package/registry/shutter-slide.json +1 -1
- package/registry/shutter-step-slices.json +1 -1
- package/registry/siri-wave.json +1 -1
- package/registry/skeleton-loader.json +1 -1
- package/registry/skeleton.json +1 -1
- package/registry/skew-x-char.json +1 -1
- package/registry/slide-down-char.json +1 -1
- package/registry/slide-down-word.json +1 -1
- package/registry/slide-left-char.json +1 -1
- package/registry/slide-left.json +1 -1
- package/registry/slide-right-char.json +1 -1
- package/registry/slide-right.json +1 -1
- package/registry/slide-up-char.json +1 -1
- package/registry/slide-up-text.json +1 -1
- package/registry/slide-up-word.json +1 -1
- package/registry/sliding-bars.json +1 -1
- package/registry/slinky-coil.json +1 -1
- package/registry/smart-card-dispenser.json +1 -1
- package/registry/smooth-dot-shift.json +1 -1
- package/registry/smooth-ring.json +1 -1
- package/registry/smooth-rounded-square.json +1 -1
- package/registry/solid-switch.json +1 -1
- package/registry/spatial-door-portal.json +1 -1
- package/registry/spinning-squares.json +1 -1
- package/registry/spiral-spinner.json +1 -1
- package/registry/split-gate-reveal.json +1 -1
- package/registry/spotlight.json +1 -1
- package/registry/spring-bars.json +1 -1
- package/registry/spring-dot-matrix.json +1 -1
- package/registry/spring-hexagon.json +1 -1
- package/registry/spring-ring-expand.json +1 -1
- package/registry/spring-text-pop.json +1 -1
- package/registry/spring-text.json +1 -1
- package/registry/square-accordion.json +1 -1
- package/registry/square-grid.json +1 -1
- package/registry/square-snake.json +1 -1
- package/registry/square-spinner.json +1 -1
- package/registry/squash-sphere.json +1 -1
- package/registry/stacked-bar-pulse.json +1 -1
- package/registry/stagger-text.json +1 -1
- package/registry/staggered-glass-curtain.json +1 -1
- package/registry/sticky-note-peel.json +1 -1
- package/registry/sticky-reveal.json +1 -1
- package/registry/stretch-x-char.json +1 -1
- package/registry/stretch-y-char.json +1 -1
- package/registry/stroke-waveform.json +1 -1
- package/registry/submenu-flyout.json +1 -1
- package/registry/success-check.json +1 -1
- package/registry/sudden-brake.json +1 -1
- package/registry/swapping-dots.json +1 -1
- package/registry/swing-word.json +1 -1
- package/registry/swirling-spinner.json +1 -1
- package/registry/symmetric-wave.json +1 -1
- package/registry/terminal-loader.json +1 -1
- package/registry/text-blink.json +1 -1
- package/registry/text-dots.json +1 -1
- package/registry/text-morph.json +1 -1
- package/registry/text-reveal.json +1 -1
- package/registry/text-shimmer-wave.json +1 -1
- package/registry/text-shimmer.json +1 -1
- package/registry/textarea-auto-grow.json +1 -1
- package/registry/theme-toggle.json +1 -1
- package/registry/tilt-card.json +1 -1
- package/registry/timer-preparation-segmented.json +1 -1
- package/registry/tracking-in-text.json +1 -1
- package/registry/tracking-out-text.json +1 -1
- package/registry/trailing-dots.json +1 -1
- package/registry/triple-dot-spinner.json +1 -1
- package/registry/twin-orbit.json +1 -1
- package/registry/typewriter-text.json +1 -1
- package/registry/typing-indicator.json +1 -1
- package/registry/typing.json +1 -1
- package/registry/use-mouse-position.json +1 -1
- package/registry/use-reduced-motion.json +1 -1
- package/registry/use-scroll-progress.json +1 -1
- package/registry/use-stagger.json +1 -1
- package/registry/use-web-haptics.json +1 -1
- package/registry/users-growth-pill-progress.json +1 -1
- package/registry/utils.json +1 -1
- package/registry/vertical-wheel-counter.json +1 -1
- package/registry/views-hourly-wave-chart.json +1 -1
- package/registry/voice-assistant-card.json +3 -3
- package/registry/wandering-cube.json +1 -1
- package/registry/wandering-eyes.json +1 -1
- package/registry/watch-spinner.json +1 -1
- package/registry/wave-dots.json +1 -1
- package/registry/wave-physics-loader.json +1 -1
- package/registry/wave-reveal.json +1 -1
- package/registry/waveform-loader.json +1 -1
- package/registry/word-reveal.json +1 -1
- package/registry/zig-zag-pulse.json +1 -1
- package/registry/zoom-in-text.json +1 -1
- package/registry/zoom-in.json +1 -1
- package/registry/zoom-out-text.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "liquid-glass-sheet",
|
|
3
3
|
"tier": "free",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.8",
|
|
5
5
|
"file": "liquid-glass-sheet.tsx",
|
|
6
6
|
"sourcePath": "ui/cards/liquid-glass-sheet.tsx",
|
|
7
7
|
"registryFile": "liquid-glass-sheet.json",
|
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
"LiquidGlassSheet",
|
|
10
10
|
"LiquidGlassSheetProps"
|
|
11
11
|
],
|
|
12
|
-
"dependencies": [
|
|
13
|
-
"lucide-react"
|
|
14
|
-
],
|
|
12
|
+
"dependencies": [],
|
|
15
13
|
"license": "MIT",
|
|
16
14
|
"previewMode": "client",
|
|
17
|
-
"content": "\"use client\";\n\"use client\";\n\n/** Original Mova implementation; visual reference documented in docs/provenance/interactive-cards.md. */\nimport * as React from \"react\";\nimport { Check, Copy, Heart, Link, Play, Share2, X } from \"lucide-react\";\n\nexport interface LiquidGlassSheetProps {\n title?: string; subtitle?: string; backgroundImage?: string; link?: string;\n defaultOpen?: boolean; onOpenChange?: (open: boolean) => void; onSaveChange?: (saved: boolean) => void;\n onPlay?: () => void; onShare?: () => void;\n theme?: \"light\" | \"dark\"; className?: string; style?: React.CSSProperties;\n}\nexport function LiquidGlassSheet({ title = \"Autumn forest\", subtitle = \"Liquid glass sheet\", backgroundImage, link = \"https://mova-ui.com\", defaultOpen = true, onOpenChange, onSaveChange, onPlay, onShare, theme = \"light\", className = \"\", style }: LiquidGlassSheetProps = {}) {\n const [open, setOpen] = React.useState(defaultOpen);\n const [saved, setSaved] = React.useState(false);\n const [status, setStatus] = React.useState(\"\");\n const [drag, setDrag] = React.useState(0);\n const start = React.useRef<number | null>(null);\n const trigger = React.useRef<HTMLButtonElement>(null);\n const panel = React.useRef<HTMLElement>(null);\n const titleId = React.useId();\n const wasOpened = React.useRef(false);\n function changeOpen(value: boolean) { setOpen(value); setDrag(0); onOpenChange?.(value); if (!value) trigger.current?.focus(); }\n React.useEffect(() => { if (open && wasOpened.current) panel.current?.querySelector<HTMLButtonElement>(\"button\")?.focus(); wasOpened.current = true; }, [open]);\n async function copy() {\n try { await navigator.clipboard.writeText(link); setStatus(\"Link copied\"); }\n catch { setStatus(\"Copy unavailable. Select the link below.\"); }\n }\n function keys(event: React.KeyboardEvent<HTMLElement>) {\n if (event.key === \"Escape\") { event.preventDefault(); changeOpen(false); }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n const buttons = Array.from(panel.current?.querySelectorAll<HTMLButtonElement>(\"button\") ?? []);\n const at = buttons.indexOf(document.activeElement as HTMLButtonElement);\n event.preventDefault(); buttons[(at + (event.key === \"ArrowDown\" ? 1 : -1) + buttons.length) % buttons.length]?.focus();\n }\n }\n return <section className={`mova-glass-sheet ${className}`} data-theme={theme} style={{ ...style, ...(backgroundImage ? { backgroundImage: `url(${JSON.stringify(backgroundImage)})` } : {}) }} aria-label={title}>\n <style>{css}</style><div className=\"mgs-forest\" aria-hidden=\"true\"><i /><i /><i /><i /><i /><i /></div>\n <button type=\"button\" className=\"mgs-trigger\" ref={trigger} aria-expanded={open} aria-controls={`${titleId}-sheet`} onClick={() => changeOpen(!open)}>{open ? \"Close sheet\" : \"Open sheet\"}</button>\n {open && <section className=\"mgs-panel\" ref={panel} id={`${titleId}-sheet`} aria-labelledby={titleId} onKeyDown={keys} style={{ transform: `translateY(${drag}px)` }}>\n <div className=\"mgs-grab\" onPointerDown={event => { start.current = event.clientY; event.currentTarget.setPointerCapture(event.pointerId); }} onPointerMove={event => { if (start.current !== null) setDrag(Math.max(0, event.clientY - start.current)); }} onPointerUp={() => { start.current = null; if (drag > 60) changeOpen(false); else setDrag(0); }} onPointerCancel={() => { start.current = null; setDrag(0); }} aria-hidden=\"true\"><span /></div>\n <header><div><h2 id={titleId}>{title}</h2><p>{subtitle}</p></div><button type=\"button\" className=\"mgs-close\" aria-label=\"Close sheet\" onClick={() => changeOpen(false)}><X size={15} /></button></header>\n <button type=\"button\" className=\"mgs-row\" onClick={() => { onPlay?.(); setStatus(\"Preview selected\"); }}><Play size={16} /><span>Play preview</span></button>\n <button type=\"button\" className=\"mgs-row\" onClick={() => { onShare?.(); if (!onShare) void copy(); else setStatus(\"Share selected\"); }}><Share2 size={16} /><span>Share</span></button>\n <button type=\"button\" className=\"mgs-row\" aria-pressed={saved} onClick={() => { setSaved(!saved); onSaveChange?.(!saved); }} >{saved ? <Check size={16} /> : <Heart size={16} />}<span>{saved ? \"Saved to favorites\" : \"Save to favorites\"}</span></button>\n <button type=\"button\" className=\"mgs-row\" onClick={() => void copy()}><Link size={16} /><span>{status === \"Link copied\" ? status : \"Copy link\"}</span><Copy size={14} /></button>\n {status && <p className=\"mgs-status\" role=\"status\">{status}{status.startsWith(\"Copy unavailable\") && <input aria-label=\"Link to copy\" readOnly value={link} onFocus={event => event.currentTarget.select()} />}</p>}\n </section>}\n </section>;\n}\nconst css = `\n.mova-glass-sheet{box-sizing:border-box;position:relative;width:320px;max-width:100%;height:380px;isolation:isolate;border-radius:24px;overflow:hidden;background:radial-gradient(ellipse at 68% 10%,#d6b85a44,transparent 50%),linear-gradient(160deg,#687349,#293e26 45%,#8a5c2f);background-size:cover;background-position:center;color:white;font:400 13px/20px -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;box-shadow:0 8px 32px #00000018}.mova-glass-sheet *{box-sizing:border-box}.mgs-forest{position:absolute;inset:0;z-index:-1;overflow:hidden;opacity:.75;background:radial-gradient(ellipse at 65% 12%,#f4d57388,transparent 40%),radial-gradient(ellipse at 20% 70%,#8d633199,transparent 40%)}.mgs-forest i{position:absolute;top:-10%;bottom:-10%;width:12px;background:linear-gradient(90deg,#16251c,#35402c,#1b291f);transform:rotate(-8deg);left:10%;box-shadow:25px 0 60px #13261f55}.mgs-forest i:nth-child(2){left:29%;width:20px;transform:rotate(8deg)}.mgs-forest i:nth-child(3){left:48%;width:8px}.mgs-forest i:nth-child(4){left:68%;width:24px;transform:rotate(5deg)}.mgs-forest i:nth-child(5){left:91%;width:18px}.mgs-forest i:nth-child(6){left:80%;width:5px;opacity:.7}.mova-glass-sheet button{font:inherit;color:inherit;cursor:pointer;border:0;background:none}.mova-glass-sheet button:focus-visible{outline:2px solid #fff;outline-offset:-3px}.mgs-trigger{position:absolute;top:24px;left:50%;transform:translateX(-50%);border:1px solid #ffffff60!important;background:#ffffff20!important;backdrop-filter:blur(10px);padding:10px 20px;border-radius:22px;white-space:nowrap;box-shadow:inset 0 1px #ffffff60,0 3px 10px #0002}.mgs-panel{position:absolute;left:8px;right:8px;bottom:8px;max-height:calc(100% - 82px);overflow:auto;border:1px solid #ffffff50;border-radius:28px;padding:0 8px 8px;background:#43513966;backdrop-filter:blur(14px) saturate(1.5);box-shadow:inset 0 1px 1px #ffffffa0,inset 0 -1px 1px #ffffff40,0 20px 44px #0004;animation:mgs-enter 300ms cubic-bezier(.2,.8,.2,1);transition:transform 180ms ease-out}.mgs-grab{height:24px;display:grid;place-items:center;touch-action:none;cursor:grab}.mgs-grab span{width:36px;height:5px;border-radius:5px;background:#ffffffb0}.mgs-panel header{display:flex;align-items:center;padding:0 12px 8px;gap:8px}.mgs-panel header>div{flex:1;min-width:0}.mgs-panel h2{margin:0;font-size:16px;line-height:22px;font-weight:500;overflow-wrap:anywhere}.mgs-panel header p{margin:0;opacity:.85;font-size:12px}.mgs-close{width:28px;height:28px;display:grid;place-items:center;border-radius:50%;flex:none}.mgs-row{display:flex;align-items:center;text-align:left;gap:10px;width:100%;min-height:42px;border-radius:15px;padding:10px!important;transition:background 160ms}.mgs-row span{flex:1;min-width:0;overflow-wrap:anywhere}.mgs-row svg{flex:none}.mgs-row:hover,.mgs-row:focus-visible,.mgs-close:hover{background:#ffffff26}.mgs-status{font-size:11px;margin:4px 12px;line-height:16px}.mgs-status input{width:100%;background:#0004;color:#fff;border:1px solid #fff8;border-radius:4px;padding:4px;font:inherit}@keyframes mgs-enter{from{opacity:0;translate:0 32px}to{opacity:1;translate:0 0}}@media(prefers-reduced-motion:reduce){.mova-glass-sheet *{animation:none!important;transition:none!important}}@media(prefers-reduced-transparency:reduce){.mgs-panel{background:#3c4a35;backdrop-filter:none}}\n`;\n"
|
|
15
|
+
"content": "\"use client\";\n\"use client\";\n\n/** Original Mova implementation; visual reference documented in docs/provenance/interactive-cards.md. */\nimport * as React from \"react\";\n\nexport interface LiquidGlassSheetProps {\n title?: string;\n subtitle?: string;\n backgroundImage?: string;\n link?: string;\n linkLabel?: string;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n onSaveChange?: (saved: boolean) => void;\n /** Reserved for applications that previously supplied this callback. */\n onPlay?: () => void;\n onShare?: () => void;\n theme?: \"light\" | \"dark\";\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst FOREST_IMAGE = \"https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?auto=format&fit=crop&q=80&w=800\";\nconst DEFAULT_LINK = \"https://liquid-glass-react-studio.vercel.app/components\";\n\n/* The red and green channels encode the surface normal of a rounded pane.\n * Its narrow curved rim bends the backdrop more strongly than its flat face. */\nfunction refractionMap(width: number, height: number, radius: number, depth: number) {\n const resolution = Math.min(1, 280 / Math.max(width, height));\n const w = Math.max(8, Math.round(width * resolution));\n const h = Math.max(8, Math.round(height * resolution));\n const canvas = document.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const context = canvas.getContext(\"2d\");\n if (!context) return \"\";\n const pixels = context.createImageData(w, h);\n const halfW = w / 2, halfH = h / 2;\n const corner = Math.min(radius * resolution, halfW - 1, halfH - 1);\n const rimWidth = Math.max(3, (4 + depth / 100 * Math.min(w, h) * .42) * resolution);\n const distance = (x: number, y: number) => {\n const qx = Math.abs(x) - halfW + corner;\n const qy = Math.abs(y) - halfH + corner;\n return Math.hypot(Math.max(0, qx), Math.max(0, qy)) + Math.min(0, Math.max(qx, qy)) - corner;\n };\n for (let index = 0; index < w * h; index++) {\n const x = index % w + .5 - halfW;\n const y = Math.floor(index / w) + .5 - halfH;\n const d = distance(x, y);\n let red = 128, green = 128;\n if (d <= .5) {\n const edge = Math.pow(1 - Math.min(1, Math.max(0, -d) / rimWidth), .72);\n const curved = edge * edge * (3 - 2 * edge);\n const dx = distance(x + 1, y) - distance(x - 1, y);\n const dy = distance(x, y + 1) - distance(x, y - 1);\n const length = Math.hypot(dx, dy) || 1;\n const face = .18 * (1 - curved);\n red = Math.round(128 + 127 * (dx / length * curved + x / halfW * face));\n green = Math.round(128 + 127 * (dy / length * curved + y / halfH * face));\n }\n pixels.data.set([Math.max(0, Math.min(255, red)), Math.max(0, Math.min(255, green)), 128, 255], index * 4);\n }\n context.putImageData(pixels, 0, 0);\n return canvas.toDataURL(\"image/png\");\n}\n\nfunction GlassMaterial({ id, width, height, radius, depth, refraction, dispersion, liquidity }: {\n id: string; width: number; height: number; radius: number; depth: number;\n refraction: number; dispersion: number; liquidity: number;\n}) {\n const [map, setMap] = React.useState(\"\");\n React.useEffect(() => { setMap(refractionMap(width, height, radius, depth)); }, [width, height, radius, depth]);\n const bend = refraction / 100 * .36;\n const spread = bend * dispersion / 100 * .4;\n const wobble = liquidity / 100 * .06;\n const channelMap = wobble > .002 ? \"warped\" : \"normal\";\n return <svg width=\"0\" height=\"0\" style={{ position: \"absolute\" }} aria-hidden=\"true\" focusable=\"false\">\n <filter id={id} x=\"-.08\" y=\"-.08\" width=\"1.16\" height=\"1.16\" filterUnits=\"objectBoundingBox\" primitiveUnits=\"objectBoundingBox\" colorInterpolationFilters=\"sRGB\">\n {map && <>\n <feImage href={map} x=\"0\" y=\"0\" width=\"1\" height=\"1\" preserveAspectRatio=\"none\" result=\"normal\" />\n {wobble > .002 && <><feTurbulence type=\"fractalNoise\" baseFrequency=\".012 .016\" numOctaves={1} seed={7} result=\"noise\" /><feDisplacementMap in=\"normal\" in2=\"noise\" scale={wobble} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"warped\" /></>}\n <feDisplacementMap in=\"SourceGraphic\" in2={channelMap} scale={Math.max(0, bend - spread)} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"red\" />\n <feColorMatrix in=\"red\" type=\"matrix\" values=\"1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"redOnly\" />\n <feDisplacementMap in=\"SourceGraphic\" in2={channelMap} scale={bend} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"green\" />\n <feColorMatrix in=\"green\" type=\"matrix\" values=\"0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0\" result=\"greenOnly\" />\n <feDisplacementMap in=\"SourceGraphic\" in2={channelMap} scale={bend + spread * 1.15} xChannelSelector=\"R\" yChannelSelector=\"G\" result=\"blue\" />\n <feColorMatrix in=\"blue\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0\" result=\"blueOnly\" />\n <feComposite in=\"redOnly\" in2=\"greenOnly\" operator=\"arithmetic\" k2=\"1\" k3=\"1\" result=\"redGreen\" />\n <feComposite in=\"redGreen\" in2=\"blueOnly\" operator=\"arithmetic\" k2=\"1\" k3=\"1\" />\n </>}\n </filter>\n </svg>;\n}\n\nfunction Icon({ kind, className = \"\", strokeWidth = 2.25, draw = false }: { kind: \"share\" | \"save\" | \"check\" | \"globe\" | \"copy\"; className?: string; strokeWidth?: number; draw?: boolean }) {\n const paths = {\n share: \"M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z\",\n save: \"M17.593 3.322c1.1.128 1.907 1.077 1.907 2.185V21L12 17.25 4.5 21V5.507c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0 1 11.186 0Z\",\n check: \"M5.25 12.7033 9.40385 17.37 18.75 6.87\",\n globe: \"M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418\",\n copy: \"M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75\",\n };\n return <svg className={`mgs-icon ${className}`} width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={strokeWidth} aria-hidden=\"true\"><path className={draw ? \"mgs-tick\" : undefined} pathLength={kind === \"check\" ? 1 : undefined} d={paths[kind]} /></svg>;\n}\n\nasync function copyText(text: string) {\n // Synchronous selection also works in embedded previews without Clipboard API permission.\n const previous = document.activeElement as HTMLElement | null;\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.readOnly = true;\n Object.assign(textarea.style, { position: \"fixed\", top: \"0\", left: \"0\", opacity: \"0\", pointerEvents: \"none\" });\n document.body.append(textarea);\n textarea.select();\n let copied = false;\n try { copied = document.execCommand(\"copy\"); } catch { /* Try the modern API below. */ }\n textarea.remove();\n previous?.focus({ preventScroll: true });\n if (copied) return true;\n try { await navigator.clipboard.writeText(text); return true; } catch { return false; }\n}\n\nexport function LiquidGlassSheet({ title = \"Autumn forest\", subtitle = \"Liquid glass sheet\", backgroundImage = FOREST_IMAGE, link = DEFAULT_LINK, linkLabel = \"liquid-glass-react-studio\", defaultOpen = true, onOpenChange, onSaveChange, onShare, theme = \"light\", className = \"\", style }: LiquidGlassSheetProps = {}) {\n const [open, setOpen] = React.useState(defaultOpen);\n const [mounted, setMounted] = React.useState(defaultOpen);\n const [saved, setSaved] = React.useState(false);\n const [status, setStatus] = React.useState<\"idle\" | \"copied\" | \"failed\">(\"idle\");\n const [touched, setTouched] = React.useState(false);\n const [highlight, setHighlight] = React.useState<number | null>(null);\n const [drag, setDrag] = React.useState(0);\n const [dragging, setDragging] = React.useState(false);\n const [closing, setClosing] = React.useState(false);\n const trigger = React.useRef<HTMLButtonElement>(null);\n const list = React.useRef<HTMLDivElement>(null);\n const dragStart = React.useRef<number | null>(null);\n const dragOffset = React.useRef(0);\n const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const closeTimer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const frames = React.useRef<number[]>([]);\n const attempt = React.useRef(0);\n const id = `mgs-${React.useId().replace(/:/g, \"\")}`;\n const wasOpened = React.useRef(false);\n React.useEffect(() => {\n if (open && wasOpened.current) list.current?.querySelector<HTMLButtonElement>(\"button\")?.focus({ preventScroll: true });\n wasOpened.current = true;\n }, [open]);\n React.useEffect(() => () => { clearTimeout(timer.current); clearTimeout(closeTimer.current); frames.current.forEach(cancelAnimationFrame); attempt.current++; }, []);\n function changeOpen(next: boolean) {\n if (next === open) return;\n clearTimeout(closeTimer.current);\n if (next) { setMounted(true); setClosing(false); }\n else { setClosing(true); setHighlight(null); closeTimer.current = setTimeout(() => { setMounted(false); setClosing(false); }, 350); }\n setOpen(next); setDrag(0); dragOffset.current = 0; dragStart.current = null; setDragging(false);\n onOpenChange?.(next);\n if (!next) requestAnimationFrame(() => trigger.current?.focus({ preventScroll: true }));\n }\n async function copy() {\n const current = ++attempt.current;\n clearTimeout(timer.current);\n frames.current.forEach(cancelAnimationFrame);\n const copied = await copyText(link);\n if (current !== attempt.current) return;\n setTouched(true); setStatus(\"idle\");\n frames.current = [requestAnimationFrame(() => {\n frames.current.push(requestAnimationFrame(() => {\n if (current !== attempt.current) return;\n setStatus(copied ? \"copied\" : \"failed\");\n timer.current = setTimeout(() => setStatus(\"idle\"), copied ? 1800 : 1400);\n }));\n })];\n }\n function keys(event: React.KeyboardEvent<HTMLElement>) {\n if (!open) return;\n if (event.key === \"Escape\") { event.preventDefault(); changeOpen(false); return; }\n if (event.key !== \"ArrowDown\" && event.key !== \"ArrowUp\") return;\n const buttons = Array.from(list.current?.querySelectorAll<HTMLButtonElement>(\"button\") ?? []);\n const index = buttons.indexOf(document.activeElement as HTMLButtonElement);\n event.preventDefault();\n buttons[(index + (event.key === \"ArrowDown\" ? 1 : -1) + buttons.length) % buttons.length]?.focus();\n }\n function endDrag(cancelled = false) {\n if (dragStart.current === null) return;\n dragStart.current = null; setDragging(false);\n if (!cancelled && dragOffset.current > 90) changeOpen(false);\n dragOffset.current = 0; setDrag(0);\n }\n const copied = status === \"copied\", failed = status === \"failed\";\n const filterStyle = { \"--mgs-pane-filter\": `url(#${id}-pane)`, \"--mgs-trigger-filter\": `url(#${id}-trigger)` } as React.CSSProperties;\n return <section className={`mova-glass-sheet${open ? \" is-open\" : \"\"} ${className}`} data-theme={theme} onKeyDown={keys} style={{ ...filterStyle, backgroundImage: `url(${JSON.stringify(backgroundImage)})`, ...style }} aria-label={title}>\n <style>{css}</style>\n <GlassMaterial id={`${id}-pane`} width={304} height={244} radius={28} depth={30} refraction={78} dispersion={42} liquidity={6} />\n <GlassMaterial id={`${id}-trigger`} width={132} height={44} radius={22} depth={26} refraction={60} dispersion={30} liquidity={4} />\n <div className={`mgs-scrim mgs-t-modal${open ? \" is-open\" : \"\"}${closing ? \" is-closing\" : \"\"}`} onClick={() => changeOpen(false)} aria-hidden=\"true\" />\n <button type=\"button\" className=\"mgs-trigger\" ref={trigger} aria-label=\"Open sheet\" aria-expanded={open} aria-controls={`${id}-sheet`} aria-hidden={open} tabIndex={open ? -1 : 0} onClick={() => changeOpen(true)}><span>Open sheet</span></button>\n <div className={`mgs-sheet${dragging ? \" is-dragging\" : \"\"}`} role=\"dialog\" aria-labelledby={`${id}-title`} aria-hidden={!open} inert={!open} id={`${id}-sheet`} style={{ \"--drag\": `${drag}px` } as React.CSSProperties}>\n <div className=\"mgs-glass\" data-open={open} />\n <div className=\"mgs-t-panel-slide mgs-panel\" data-open={open}>\n {mounted && <div className=\"mgs-body\">\n <button type=\"button\" className=\"mgs-grab\" aria-label=\"Drag down to close\" onPointerDown={event => { event.currentTarget.setPointerCapture(event.pointerId); dragStart.current = event.clientY; setDragging(true); }} onPointerMove={event => {\n if (dragStart.current === null) return;\n const delta = event.clientY - dragStart.current;\n dragOffset.current = delta >= 0 ? delta : -Math.pow(-delta, .6) * 2;\n setDrag(dragOffset.current);\n }} onPointerUp={() => endDrag()} onPointerCancel={() => endDrag(true)} onClick={event => { if (event.detail === 0) changeOpen(false); }}><span /></button>\n <header className=\"mgs-head\"><h2 id={`${id}-title`} className=\"mgs-title\">{title}</h2><p className=\"mgs-meta\">{subtitle}</p></header>\n <div className=\"mgs-list\" ref={list} onMouseLeave={() => setHighlight(null)}>\n <span className=\"mgs-hl\" style={{ transform: `translateY(${(highlight ?? 0) * 44}px)`, opacity: highlight === null ? 0 : 1 }} />\n <button type=\"button\" className=\"mgs-row\" onMouseEnter={() => setHighlight(0)} onFocus={() => setHighlight(0)} onBlur={() => setHighlight(null)} onClick={() => { onShare?.(); changeOpen(false); }}><Icon kind=\"share\" /><span className=\"mgs-label\">Share</span></button>\n <button type=\"button\" className={`mgs-row${saved ? \" mgs-saved\" : \"\"}`} aria-pressed={saved} onMouseEnter={() => setHighlight(1)} onFocus={() => setHighlight(1)} onBlur={() => setHighlight(null)} onClick={() => { setSaved(!saved); onSaveChange?.(!saved); }}><span className=\"mgs-slot\"><Icon kind=\"save\" className=\"mgs-icon-a\" /><Icon kind=\"check\" className=\"mgs-icon-b\" strokeWidth={3} /></span><span className=\"mgs-label\">{saved ? \"Saved\" : \"Save\"}</span></button>\n <div className={`mgs-linkrow${copied ? \" is-copied\" : \"\"}${failed ? \" is-failed\" : \"\"}`} onMouseEnter={() => setHighlight(2)} onFocus={() => setHighlight(2)} onBlur={() => setHighlight(null)}>\n <button type=\"button\" className=\"mgs-row mgs-linkmain\" aria-label={copied ? \"Link copied\" : failed ? \"Copy blocked\" : \"Copy link\"} onClick={() => void copy()}><span className=\"mgs-slot\"><Icon kind=\"globe\" className=\"mgs-icon-a\" /><Icon kind=\"check\" className=\"mgs-icon-b\" strokeWidth={3} draw /></span><span key={status} className={`mgs-label${touched ? \" mgs-label-anim\" : \"\"}`}>{copied ? \"Link copied\" : failed ? \"Copy blocked\" : linkLabel}</span></button>\n <button type=\"button\" className=\"mgs-copy\" aria-label=\"Copy link\" onClick={() => void copy()}><Icon kind=\"copy\" /></button>\n </div>\n </div>\n </div>}\n </div>\n </div>\n <span className=\"mgs-status\" role=\"status\" aria-live=\"polite\">{copied ? \"Link copied\" : failed ? \"Copy blocked\" : \"\"}</span>\n </section>;\n}\n\nconst css = `\n.mova-glass-sheet{\n --panel-open-dur: 400ms;\n --panel-close-dur: 350ms;\n --panel-translate-y: 100px;\n --panel-blur: 2px;\n --panel-ease: cubic-bezier(0.22, 1, 0.36, 1);\n --modal-open-dur: 250ms;\n --modal-close-dur: 150ms;\n --modal-scale: 0.96;\n --modal-scale-close: 0.96;\n --modal-ease: cubic-bezier(0.22, 1, 0.36, 1);\n --scrim-dur:150ms;\n --hl-dur:250ms;\n --hl-ease:cubic-bezier(0.22,1,0.36,1);\n --icon-dur:250ms;\n --press-scale:0.97;\n --press-dur:150ms;\n --ease-smooth-out:cubic-bezier(0.22,1,0.36,1);\n --ease-spring:cubic-bezier(0.34, 1.56, 0.64, 1);\n --mgs-ease-out: cubic-bezier(0.22, 1, 0.36, 1);\n --mgs-ease-liquid: cubic-bezier(0.16, 1, 0.3, 1);\n --mgs-press: 160ms;\n}\n\n.mova-glass-sheet{position:relative;box-sizing:border-box;width:320px;max-width:100%;height:360px;font:400 13px/20px Inter,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;border-radius:24px;overflow:hidden;background-size:cover;background-position:center;box-shadow:0 0 0 1px rgba(0,0,0,.04),0 8px 32px -4px rgba(0,0,0,.06),0 1px 3px 0 rgba(0,0,0,.04);color:#fff}\n.mova-glass-sheet :is(button,a){font:inherit;color:inherit;text-decoration:none}\n.mova-glass-sheet :where(button){border:0;background:none;padding:0;cursor:pointer}\n.mgs-scrim{position:absolute;inset:0;background:rgba(0,0,0,.28)}\n\n/* ───────── Compact iOS 26 glass trigger (44px full-round capsule) ───────── */\n.mova-glass-sheet .mgs-trigger{\n position:absolute;\n left:50%;\n bottom:28px;\n translate:-50% 0;\n isolation:isolate;\n overflow:hidden;\n box-sizing:border-box;\n width:auto;\n height:44px;\n padding:0 22px;\n border-radius:999px;\n display:inline-flex;\n align-items:center;\n justify-content:center;\n white-space:nowrap;\n color:#fff;\n font-size:15px;\n line-height:20px;\n font-weight:600;\n letter-spacing:-0.01em;\n text-shadow:0 1px 2px rgb(0 0 0 / 0.25);\n background:rgb(255 255 255 / 0.10);\n -webkit-backdrop-filter:var(--mgs-trigger-filter) blur(2px) saturate(170%);\n backdrop-filter:var(--mgs-trigger-filter) blur(2px) saturate(170%);\n box-shadow:\n inset 1.5px 1.5px 0.5px -0.5px rgb(255 255 255 / 0.12),\n inset -1px -1px 0.5px -0.5px rgb(255 255 255 / 0.04),\n inset 0 0 0 1px rgb(255 255 255 / 0.18),\n 0 0 0 0.5px rgb(255 255 255 / 0.22),\n 0 8px 24px rgb(0 0 0 / 0.18);\n transition:\n transform 380ms var(--ease-spring),\n box-shadow var(--mgs-press) var(--mgs-ease-out),\n opacity var(--scrim-dur) var(--ease-smooth-out);\n}\n.mgs-trigger::before{\n content:\"\";\n position:absolute;\n inset:0;\n z-index:-1;\n border-radius:inherit;\n pointer-events:none;\n background:radial-gradient(70% 55% at 69.8% 30.2%, rgb(255 255 255 / 0.035) 0%, transparent 46%);\n mix-blend-mode:plus-lighter;\n opacity:0;\n transition:opacity 240ms var(--mgs-ease-out);\n}\n.mgs-trigger:hover::before{opacity:1}\n.mgs-trigger::after{\n content:\"\";\n position:absolute;\n inset:0;\n z-index:-1;\n border-radius:inherit;\n pointer-events:none;\n background:radial-gradient(circle at 50% 50%, rgb(255 255 255 / 0.95) 0%, rgb(255 255 255 / 0.48) 22%, rgb(255 255 255 / 0.1) 48%, transparent 65%);\n mix-blend-mode:plus-lighter;\n opacity:0;\n transform:scale(0.65);\n transition:opacity var(--mgs-press) var(--mgs-ease-out), transform var(--mgs-press) var(--mgs-ease-out);\n}\n.mgs-trigger:active{transform:scale(0.94)}\n.mgs-trigger:active::before{opacity:1}\n.mgs-trigger:active::after{opacity:0.110;transform:scale(1)}\n.mova-glass-sheet.is-open .mgs-trigger{opacity:0;pointer-events:none}\n\n@supports not (backdrop-filter: url(#mgs-filter)){\n .mova-glass-sheet .mgs-trigger{\n -webkit-backdrop-filter:blur(25px) saturate(160%) brightness(1.06);\n backdrop-filter:blur(25px) saturate(160%) brightness(1.06);\n background:linear-gradient(145deg, rgb(255 255 255 / 0.015) 0%, rgb(255 255 255 / 0.004) 45%, rgb(255 255 255 / 0.096) 100%);\n box-shadow:\n inset 2px 2px 1px -0.5px rgb(255 255 255 / 0.066),\n inset -1.5px -1.5px 1px -0.5px rgb(255 255 255 / 0.025),\n inset 0 0 0 1.2px rgb(255 255 255 / 0.224),\n 0 20px 48px rgb(0 0 0 / 0.24);\n }\n .mgs-trigger::before{opacity:0.75}\n}\n@media (prefers-reduced-transparency: reduce){\n .mova-glass-sheet .mgs-trigger{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgb(255 255 255 / 0.88);color:#111;text-shadow:none}\n}\n\n/* ───────── Sheet ───────── */\n.mgs-sheet{position:absolute;left:8px;right:8px;bottom:8px;height:244px;border-radius:28px;transform:translateY(var(--drag,0px));transition:transform var(--panel-open-dur) var(--panel-ease);touch-action:none;pointer-events:none}\n.mova-glass-sheet.is-open .mgs-sheet{pointer-events:auto}\n.mgs-panel{position:absolute;inset:0}\n.mgs-sheet.is-dragging{transition:none!important}\n\n/* ───────── REAL LIQUID GLASS MATERIAL ───────── */\n.mgs-glass{\n position:absolute;\n inset:0;\n isolation:isolate;\n overflow:hidden;\n border-radius:28px;\n corner-shape:squircle;\n pointer-events:none;\n background:rgb(255 255 255 / 0.080);\n -webkit-backdrop-filter:var(--mgs-pane-filter) blur(3px) saturate(160%);\n backdrop-filter:var(--mgs-pane-filter) blur(3px) saturate(160%);\n box-shadow:\n inset 1.5px 1.5px 0.5px -0.5px rgb(255 255 255 / 0.055),\n inset -1px -1px 0.5px -0.5px rgb(255 255 255 / 0.018),\n inset 0 0 0 1.2px rgb(255 255 255 / 0.140),\n 0 0 0 0.5px rgb(255 255 255 / 0.22),\n 0 18px 40px rgb(0 0 0 / 0.2);\n transform:translateY(var(--panel-translate-y));\n opacity:0;\n transition:\n transform var(--panel-close-dur) var(--panel-ease),\n opacity var(--panel-close-dur) var(--panel-ease),\n box-shadow var(--mgs-press) var(--mgs-ease-out);\n}\n.mgs-glass[data-open=\"true\"]{\n transform:none;\n opacity:1;\n transition:\n transform var(--panel-open-dur) var(--panel-ease),\n opacity var(--panel-open-dur) var(--panel-ease),\n box-shadow var(--mgs-press) var(--mgs-ease-out);\n}\n.mgs-glass::before{\n content:\"\";\n position:absolute;\n inset:0;\n z-index:-1;\n border-radius:inherit;\n pointer-events:none;\n background:radial-gradient(70% 55% at 69.8% 30.2%, rgb(255 255 255 / 0.035) 0%, transparent 46%);\n mix-blend-mode:plus-lighter;\n opacity:0;\n transition:opacity 240ms var(--mgs-ease-out);\n}\n.mgs-sheet:hover .mgs-glass::before{opacity:1}\n.mgs-glass::after{\n content:\"\";\n position:absolute;\n inset:0;\n z-index:-1;\n border-radius:inherit;\n pointer-events:none;\n background:radial-gradient(circle at 50% 50%, rgb(255 255 255 / 0.95) 0%, rgb(255 255 255 / 0.48) 22%, rgb(255 255 255 / 0.1) 48%, transparent 65%);\n mix-blend-mode:plus-lighter;\n opacity:0;\n transform:scale(0.65);\n transition:opacity var(--mgs-press) var(--mgs-ease-out), transform var(--mgs-press) var(--mgs-ease-out);\n}\n.mgs-sheet:active .mgs-glass::before{opacity:1}\n.mgs-sheet:active .mgs-glass::after{opacity:0.110;transform:scale(1)}\n\n@supports not (backdrop-filter: url(#mgs-filter)){\n .mgs-glass{\n -webkit-backdrop-filter:blur(25px) saturate(160%) brightness(1.06);\n backdrop-filter:blur(25px) saturate(160%) brightness(1.06);\n background:linear-gradient(145deg, rgb(255 255 255 / 0.015) 0%, rgb(255 255 255 / 0.004) 45%, rgb(255 255 255 / 0.096) 100%);\n box-shadow:\n inset 2px 2px 1px -0.5px rgb(255 255 255 / 0.066),\n inset -1.5px -1.5px 1px -0.5px rgb(255 255 255 / 0.025),\n inset 0 0 0 1.2px rgb(255 255 255 / 0.224),\n 0 20px 48px rgb(0 0 0 / 0.24);\n }\n .mgs-glass::before{opacity:0.75}\n}\n@media (prefers-reduced-transparency: reduce){\n .mgs-glass{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgb(255 255 255 / 0.88)}\n}\n\n/* ───────── Body / grabber / header ───────── */\n.mgs-body{position:relative;padding:0 8px 8px}\n.mgs-grab{display:flex;justify-content:center;width:100%;height:24px;align-items:center;cursor:grab;touch-action:none}\n.mgs-grab:is(:active,.is-pressed){cursor:grabbing}\n.mgs-grab span{width:36px;height:5px;border-radius:5px;background:rgba(255,255,255,.7)}\n.mgs-head{padding:0 12px 8px}\n.mgs-title{margin:0;font-size:16px;line-height:22px;font-weight:500}\n.mgs-meta{margin:0;font-size:12px;line-height:16px;color:rgba(255,255,255,.85)}\n\n/* ───────── List / rows / highlight ───────── */\n.mgs-list{position:relative;display:flex;flex-direction:column;margin-top:4px}\n.mgs-hl{position:absolute;left:0;right:0;top:0;height:44px;border-radius:16px;background:rgba(255,255,255,.2);box-shadow:inset 0 0 0 1px rgba(255,255,255,.18);opacity:0;transition:transform var(--hl-dur) var(--hl-ease),opacity var(--hl-dur) var(--hl-ease);pointer-events:none}\n.mgs-row{box-sizing:border-box;position:relative;display:flex;align-items:center;gap:8px;height:44px;padding:0 12px 0 10px;border-radius:16px;font-size:13px;line-height:20px;text-align:left;width:100%;outline:none}\n.mgs-row .mgs-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.mgs-row:focus-visible{box-shadow:0 0 0 2px rgba(255,255,255,.9)}\n.mgs-row .mgs-icon{flex:none}\n.mgs-slot{position:relative;width:16px;height:16px;flex:none}\n.mgs-slot .mgs-icon{position:absolute;inset:0;transition:opacity var(--icon-dur) ease-in-out,transform var(--icon-dur) ease-in-out,filter var(--icon-dur) ease-in-out}\n.mgs-slot .mgs-icon-b{opacity:0;transform:scale(.25);filter:blur(2px)}\n.mgs-saved .mgs-slot .mgs-icon-a{opacity:0;transform:scale(.25);filter:blur(2px)}\n.mgs-saved .mgs-slot .mgs-icon-b{opacity:1;transform:scale(1);filter:blur(0)}\n\n/* ───────── Link row ───────── */\n.mgs-linkrow{position:relative;display:flex;align-items:center;height:44px;border-radius:16px}\n.mgs-linkrow .mgs-row{flex:1;min-width:0;width:auto;padding-right:6px}\n\n/* the link itself: soft flash when copied, shake when blocked */\n.mgs-linkmain{cursor:pointer;transition:transform 380ms var(--ease-spring)}\n.mgs-linkmain:active{transform:scale(var(--press-scale))}\n.mgs-linkrow.is-copied .mgs-linkmain{animation:mgs-row-flash 700ms var(--mgs-ease-out)}\n.mgs-linkrow.is-failed .mgs-linkmain{animation:mgs-copy-shake 420ms var(--mgs-ease-out)}\n\n/* link icon: globe -> drawn checkmark */\n.mgs-linkrow.is-copied .mgs-linkmain .mgs-slot .mgs-icon-a{opacity:0;transform:scale(.25) rotate(-25deg);filter:blur(2px)}\n.mgs-linkrow.is-copied .mgs-linkmain .mgs-slot .mgs-icon-b{opacity:1;transform:scale(1);filter:blur(0)}\n.mgs-tick{stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 380ms var(--mgs-ease-out)}\n.mgs-linkrow.is-copied .mgs-linkmain .mgs-tick{stroke-dashoffset:0;transition-delay:140ms}\n\n/* corner copy icon: static, no copied/failed animation */\n.mgs-linkrow .mgs-copy{\n position:relative;\n display:grid;\n place-items:center;\n flex:none;\n width:32px;\n height:32px;\n margin-right:6px;\n border-radius:11px;\n corner-shape:squircle;\n outline:none;\n color:rgba(255,255,255,.85);\n background:transparent;\n}\n@media (hover: hover) and (pointer: fine){\n .mgs-linkrow .mgs-copy:hover{background:rgba(255,255,255,.18);color:#fff}\n}\n.mgs-linkrow .mgs-copy:focus-visible{box-shadow:0 0 0 2px rgba(255,255,255,.9)}\n\n/* label swaps with a soft blur-in */\n.mgs-label-anim{animation:mgs-label-in 320ms var(--mgs-ease-out)}\n\n@keyframes mgs-copy-shake{0%,100%{transform:translateX(0)}20%{transform:translateX(-4px)}40%{transform:translateX(4px)}60%{transform:translateX(-3px)}80%{transform:translateX(2px)}}\n@keyframes mgs-label-in{from{opacity:0;transform:translateY(6px);filter:blur(3px)}to{opacity:1;transform:none;filter:blur(0)}}\n@keyframes mgs-row-flash{0%{background:rgba(255,255,255,.26)}100%{background:rgba(255,255,255,0)}}\n\n/* ───────── Motion helpers ───────── */\n.mgs-t-panel-slide{transform:translateY(var(--panel-translate-y));opacity:0;filter:blur(var(--panel-blur));pointer-events:none;transition:transform var(--panel-close-dur) var(--panel-ease),opacity var(--panel-close-dur) var(--panel-ease),filter var(--panel-close-dur) var(--panel-ease)}\n.mgs-t-panel-slide[data-open=\"true\"]{transform:translateY(0);opacity:1;filter:none;pointer-events:auto;transition:transform var(--panel-open-dur) var(--panel-ease),opacity var(--panel-open-dur) var(--panel-ease),filter var(--panel-open-dur) var(--panel-ease)}\n.mgs-t-modal{transform-origin:center;transform:scale(var(--modal-scale));opacity:0;pointer-events:none;transition:transform var(--modal-open-dur) var(--modal-ease),opacity var(--modal-open-dur) var(--modal-ease)}\n.mgs-t-modal.is-open{transform:scale(1);opacity:1;pointer-events:auto}\n.mgs-t-modal.is-closing{transform:scale(var(--modal-scale-close));opacity:0;pointer-events:none;transition:transform var(--modal-close-dur) var(--modal-ease),opacity var(--modal-close-dur) var(--modal-ease)}\n@media (prefers-reduced-motion:reduce){\n .mgs-sheet,.mgs-t-panel-slide,.mgs-t-modal,.mgs-hl,.mgs-scrim,.mgs-trigger,.mgs-trigger::before,.mgs-trigger::after,.mgs-slot .mgs-icon,.mgs-glass,.mgs-glass::before,.mgs-glass::after,.mgs-linkmain,.mgs-tick{transition:none!important}\n .mgs-label-anim,.mgs-linkrow.is-copied .mgs-linkmain,.mgs-linkrow.is-failed .mgs-linkmain{animation:none!important}\n}\n\n.mgs-icon-play{translate:1px 0}.mgs-icon-heart{translate:0 1px}\n\n.mova-glass-sheet :where(button,[role=\"button\"],[role=\"tab\"],[role=\"menuitem\"],[role=\"menuitemcheckbox\"],[role=\"menuitemradio\"],[role=\"option\"],[role=\"switch\"],summary,.t-pressable){-webkit-tap-highlight-color:transparent;touch-action:manipulation;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}\n\n.mova-glass-sheet *{box-sizing:border-box}.mgs-trigger:focus-visible,.mgs-grab:focus-visible{outline:2px solid #fff;outline-offset:-3px}.mgs-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n`;\n"
|
|
18
16
|
}
|