@particle-academy/react-fancy 4.8.1 → 4.9.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/dist/styles.css CHANGED
@@ -77,6 +77,52 @@
77
77
  :where(.dark [data-react-fancy-context-menu-separator]) {
78
78
  background-color: #3f3f46;
79
79
  }
80
+ .fancy-checkerboard {
81
+ background-color: #ffffff;
82
+ background-image:
83
+ linear-gradient(
84
+ 45deg,
85
+ #e5e7eb 25%,
86
+ transparent 25%),
87
+ linear-gradient(
88
+ -45deg,
89
+ #e5e7eb 25%,
90
+ transparent 25%),
91
+ linear-gradient(
92
+ 45deg,
93
+ transparent 75%,
94
+ #e5e7eb 75%),
95
+ linear-gradient(
96
+ -45deg,
97
+ transparent 75%,
98
+ #e5e7eb 75%);
99
+ background-size: 16px 16px;
100
+ background-position:
101
+ 0 0,
102
+ 0 8px,
103
+ 8px -8px,
104
+ -8px 0;
105
+ }
106
+ :where(.dark) .fancy-checkerboard {
107
+ background-color: #18181b;
108
+ background-image:
109
+ linear-gradient(
110
+ 45deg,
111
+ #27272a 25%,
112
+ transparent 25%),
113
+ linear-gradient(
114
+ -45deg,
115
+ #27272a 25%,
116
+ transparent 25%),
117
+ linear-gradient(
118
+ 45deg,
119
+ transparent 75%,
120
+ #27272a 75%),
121
+ linear-gradient(
122
+ -45deg,
123
+ transparent 75%,
124
+ #27272a 75%);
125
+ }
80
126
  @keyframes fancy-fade-in {
81
127
  from {
82
128
  opacity: 0;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/react-fancy — base styles + animations */\n\n/* ─── Input & Field defaults ─────────────────────────────────────────────────\n Better UX out of the box: spacing between stacked fields, smooth transitions,\n and polished dark-mode defaults. All overridable via data-attribute selectors.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Field spacing — adjacent fields get vertical breathing room */\n[data-react-fancy-field] + [data-react-fancy-field] {\n margin-top: 1rem;\n}\n\n/* Smooth transitions on all text inputs, selects, and textareas */\n[data-react-fancy-input] input,\n[data-react-fancy-textarea],\n[data-react-fancy-select],\n[data-react-fancy-date-picker],\n[data-react-fancy-autocomplete] input,\n[data-react-fancy-pillbox],\n[data-react-fancy-otp-input] input,\n[data-react-fancy-time-picker] input,\n[data-react-fancy-color-picker] input {\n transition: border-color 0.15s ease, box-shadow 0.15s ease,\n background-color 0.15s ease;\n}\n\n/* Dark-mode input refinements — slightly darker bg for contrast against page */\n/* ─── Inherent dark-mode defaults ────────────────────────────────────────────\n Every rule below is wrapped in :where() so it carries ZERO specificity, which\n buys two properties at once:\n 1. Inherent — a sensible dark appearance ships out of the box, even when the\n consumer's Tailwind build doesn't generate react-fancy's `dark:` utility\n classes (e.g. they didn't @source the package). This is what lets the\n overlays (Dropdown, Menu, Popover, …) go dark on their own.\n 2. Override-friendly — because specificity is 0, ANY consumer override wins:\n a plain `dark:bg-…` utility, a custom class, or the component's own\n `dark:` class (when it IS generated) all take precedence — no !important,\n no need to target the data-attribute.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Inputs / selects / textareas — darker bg for contrast against the page */\n:where(.dark [data-react-fancy-input] input),\n:where(.dark [data-react-fancy-textarea]),\n:where(.dark [data-react-fancy-select]),\n:where(.dark [data-react-fancy-date-picker]),\n:where(.dark [data-react-fancy-autocomplete] input),\n:where(.dark [data-react-fancy-pillbox]),\n:where(.dark [data-react-fancy-otp-input] input),\n:where(.dark [data-react-fancy-time-picker] input) {\n background-color: #1e1e24;\n border-color: #3f3f46;\n}\n\n/* Focus ring — brighter border + subtle glow */\n:where(.dark [data-react-fancy-input] input:focus),\n:where(.dark [data-react-fancy-textarea]:focus),\n:where(.dark [data-react-fancy-select]:focus),\n:where(.dark [data-react-fancy-date-picker]:focus),\n:where(.dark [data-react-fancy-autocomplete] input:focus),\n:where(.dark [data-react-fancy-otp-input] input:focus),\n:where(.dark [data-react-fancy-time-picker] input:focus) {\n border-color: #60a5fa;\n box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.15);\n}\n\n/* Field labels — brighter for readability */\n:where(.dark [data-react-fancy-field] > label:first-child) {\n color: #f4f4f5;\n}\n\n/* Checkbox & radio */\n:where(.dark [data-react-fancy-checkbox] input),\n:where(.dark [data-react-fancy-radio-group] input) {\n background-color: #1e1e24;\n border-color: #3f3f46;\n}\n\n/* Switch unchecked track */\n:where(.dark [data-react-fancy-switch] button[aria-checked=\"false\"]) {\n background-color: #3f3f46;\n}\n\n/* Input wrapper affixes */\n:where(.dark [data-react-fancy-input-wrapper] > span:first-child),\n:where(.dark [data-react-fancy-input-wrapper] > span:last-child) {\n border-color: #3f3f46;\n background-color: #27272a;\n}\n\n/* Date picker icon (calendar, clock) */\n:where(.dark [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator) {\n filter: invert(0.8);\n}\n\n/* ─── Overlays — inherent dark surfaces ──────────────────────────────────────\n Dropdown / Menu / Popover / ContextMenu / MobileMenu flyout / Modal / Toast.\n Mirrors the components' own `dark:` utilities (zinc-900 surface, zinc-700\n border, zinc-300 text) so overlays render correctly in dark mode WITHOUT the\n consumer @sourcing react-fancy. When those utilities ARE generated they win\n (specificity 0 here), so there's no drift or double-styling. */\n:where(.dark [data-react-fancy-dropdown]),\n:where(.dark [data-react-fancy-menu]),\n:where(.dark [data-react-fancy-popover]),\n:where(.dark [data-react-fancy-context-menu]),\n:where(.dark [data-react-fancy-context-menu-sub-content]),\n:where(.dark [data-react-fancy-mobile-menu-flyout]),\n:where(.dark [data-react-fancy-modal]),\n:where(.dark [data-react-fancy-toast-item]) {\n background-color: #18181b; /* zinc-900 */\n border-color: #3f3f46; /* zinc-700 */\n color: #d4d4d8; /* zinc-300 */\n}\n\n/* Overlay item hover states */\n:where(.dark [data-react-fancy-dropdown-item]:hover),\n:where(.dark [data-react-fancy-menu-item]:hover),\n:where(.dark [data-react-fancy-context-menu-item]:hover) {\n background-color: #27272a; /* zinc-800 */\n}\n\n/* Overlay separators */\n:where(.dark [data-react-fancy-dropdown-separator]),\n:where(.dark [data-react-fancy-context-menu-separator]) {\n background-color: #3f3f46; /* zinc-700 */\n}\n\n@keyframes fancy-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-left {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-right {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n.fancy-fade-in {\n animation: fancy-fade-in 0.2s ease-out;\n}\n\n.fancy-slide-left {\n animation: fancy-slide-left 0.3s ease-out;\n}\n\n.fancy-slide-right {\n animation: fancy-slide-right 0.3s ease-out;\n}\n\n/* Overlay / floating animations */\n\n@keyframes fancy-scale-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes fancy-slide-up {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n@keyframes fancy-toast-in {\n from {\n opacity: 0;\n transform: translateX(100%);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-collapse-open {\n from {\n grid-template-rows: 0fr;\n }\n to {\n grid-template-rows: 1fr;\n }\n}\n\n@keyframes fancy-collapse-close {\n from {\n grid-template-rows: 1fr;\n }\n to {\n grid-template-rows: 0fr;\n }\n}\n\n.fancy-scale-in {\n animation: fancy-scale-in 0.15s ease-out;\n}\n\n.fancy-slide-up {\n animation: fancy-slide-up 0.2s ease-out;\n}\n\n.fancy-fade-out {\n animation: fancy-fade-out 0.15s ease-in forwards;\n}\n\n.fancy-toast-in {\n animation: fancy-toast-in 0.3s ease-out;\n}\n\n.fancy-collapse-open {\n animation: fancy-collapse-open 0.2s ease-out forwards;\n}\n\n.fancy-collapse-close {\n animation: fancy-collapse-close 0.15s ease-in forwards;\n}\n\n/* Mobile flyout slide animations */\n\n@keyframes fancy-slide-in-left {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-out-left {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n}\n\n@keyframes fancy-slide-in-right {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n/* Avatar glow — a looping halo ring (box-shadow only, no reflow). Color comes\n from the --fancy-glow custom property set on the element. */\n@keyframes fancy-avatar-glow {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 55%, transparent);\n opacity: 0.9;\n }\n 70% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.5;\n }\n 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.9;\n }\n}\n\n.fancy-avatar-glow {\n position: absolute;\n inset: 0;\n border-radius: 9999px;\n pointer-events: none;\n box-shadow:\n 0 0 0 2px color-mix(in srgb, var(--fancy-glow, #a855f7) 70%, transparent),\n 0 0 10px 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 45%, transparent);\n animation: fancy-avatar-glow 1.6s ease-out infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-avatar-glow {\n animation: none;\n }\n}\n\n@keyframes fancy-slide-out-right {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n.fancy-slide-in-left {\n animation: fancy-slide-in-left 0.25s ease-out;\n}\n\n.fancy-slide-out-left {\n animation: fancy-slide-out-left 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-right {\n animation: fancy-slide-in-right 0.25s ease-out;\n}\n\n.fancy-slide-out-right {\n animation: fancy-slide-out-right 0.2s ease-in forwards;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/styles.css"],"sourcesContent":["/* @particle-academy/react-fancy — base styles + animations */\n\n/* ─── Input & Field defaults ─────────────────────────────────────────────────\n Better UX out of the box: spacing between stacked fields, smooth transitions,\n and polished dark-mode defaults. All overridable via data-attribute selectors.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Field spacing — adjacent fields get vertical breathing room */\n[data-react-fancy-field] + [data-react-fancy-field] {\n margin-top: 1rem;\n}\n\n/* Smooth transitions on all text inputs, selects, and textareas */\n[data-react-fancy-input] input,\n[data-react-fancy-textarea],\n[data-react-fancy-select],\n[data-react-fancy-date-picker],\n[data-react-fancy-autocomplete] input,\n[data-react-fancy-pillbox],\n[data-react-fancy-otp-input] input,\n[data-react-fancy-time-picker] input,\n[data-react-fancy-color-picker] input {\n transition: border-color 0.15s ease, box-shadow 0.15s ease,\n background-color 0.15s ease;\n}\n\n/* Dark-mode input refinements — slightly darker bg for contrast against page */\n/* ─── Inherent dark-mode defaults ────────────────────────────────────────────\n Every rule below is wrapped in :where() so it carries ZERO specificity, which\n buys two properties at once:\n 1. Inherent — a sensible dark appearance ships out of the box, even when the\n consumer's Tailwind build doesn't generate react-fancy's `dark:` utility\n classes (e.g. they didn't @source the package). This is what lets the\n overlays (Dropdown, Menu, Popover, …) go dark on their own.\n 2. Override-friendly — because specificity is 0, ANY consumer override wins:\n a plain `dark:bg-…` utility, a custom class, or the component's own\n `dark:` class (when it IS generated) all take precedence — no !important,\n no need to target the data-attribute.\n ──────────────────────────────────────────────────────────────────────────── */\n\n/* Inputs / selects / textareas — darker bg for contrast against the page */\n:where(.dark [data-react-fancy-input] input),\n:where(.dark [data-react-fancy-textarea]),\n:where(.dark [data-react-fancy-select]),\n:where(.dark [data-react-fancy-date-picker]),\n:where(.dark [data-react-fancy-autocomplete] input),\n:where(.dark [data-react-fancy-pillbox]),\n:where(.dark [data-react-fancy-otp-input] input),\n:where(.dark [data-react-fancy-time-picker] input) {\n background-color: #1e1e24;\n border-color: #3f3f46;\n}\n\n/* Focus ring — brighter border + subtle glow */\n:where(.dark [data-react-fancy-input] input:focus),\n:where(.dark [data-react-fancy-textarea]:focus),\n:where(.dark [data-react-fancy-select]:focus),\n:where(.dark [data-react-fancy-date-picker]:focus),\n:where(.dark [data-react-fancy-autocomplete] input:focus),\n:where(.dark [data-react-fancy-otp-input] input:focus),\n:where(.dark [data-react-fancy-time-picker] input:focus) {\n border-color: #60a5fa;\n box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.15);\n}\n\n/* Field labels — brighter for readability */\n:where(.dark [data-react-fancy-field] > label:first-child) {\n color: #f4f4f5;\n}\n\n/* Checkbox & radio */\n:where(.dark [data-react-fancy-checkbox] input),\n:where(.dark [data-react-fancy-radio-group] input) {\n background-color: #1e1e24;\n border-color: #3f3f46;\n}\n\n/* Switch unchecked track */\n:where(.dark [data-react-fancy-switch] button[aria-checked=\"false\"]) {\n background-color: #3f3f46;\n}\n\n/* Input wrapper affixes */\n:where(.dark [data-react-fancy-input-wrapper] > span:first-child),\n:where(.dark [data-react-fancy-input-wrapper] > span:last-child) {\n border-color: #3f3f46;\n background-color: #27272a;\n}\n\n/* Date picker icon (calendar, clock) */\n:where(.dark [data-react-fancy-date-picker]::-webkit-calendar-picker-indicator) {\n filter: invert(0.8);\n}\n\n/* ─── Overlays — inherent dark surfaces ──────────────────────────────────────\n Dropdown / Menu / Popover / ContextMenu / MobileMenu flyout / Modal / Toast.\n Mirrors the components' own `dark:` utilities (zinc-900 surface, zinc-700\n border, zinc-300 text) so overlays render correctly in dark mode WITHOUT the\n consumer @sourcing react-fancy. When those utilities ARE generated they win\n (specificity 0 here), so there's no drift or double-styling. */\n:where(.dark [data-react-fancy-dropdown]),\n:where(.dark [data-react-fancy-menu]),\n:where(.dark [data-react-fancy-popover]),\n:where(.dark [data-react-fancy-context-menu]),\n:where(.dark [data-react-fancy-context-menu-sub-content]),\n:where(.dark [data-react-fancy-mobile-menu-flyout]),\n:where(.dark [data-react-fancy-modal]),\n:where(.dark [data-react-fancy-toast-item]) {\n background-color: #18181b; /* zinc-900 */\n border-color: #3f3f46; /* zinc-700 */\n color: #d4d4d8; /* zinc-300 */\n}\n\n/* Overlay item hover states */\n:where(.dark [data-react-fancy-dropdown-item]:hover),\n:where(.dark [data-react-fancy-menu-item]:hover),\n:where(.dark [data-react-fancy-context-menu-item]:hover) {\n background-color: #27272a; /* zinc-800 */\n}\n\n/* Overlay separators */\n:where(.dark [data-react-fancy-dropdown-separator]),\n:where(.dark [data-react-fancy-context-menu-separator]) {\n background-color: #3f3f46; /* zinc-700 */\n}\n\n/* ─── Media viewer — transparency checkerboard ───────────────────────────────\n Backdrop for <ImageViewer> / <MediaViewer> so transparent images read clearly.\n Light + dark variants; the dark rule is wrapped in :where() (zero specificity)\n so it ships out of the box without the consumer @sourcing react-fancy. */\n.fancy-checkerboard {\n background-color: #ffffff;\n background-image:\n linear-gradient(45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #e5e7eb 75%),\n linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n}\n\n:where(.dark) .fancy-checkerboard {\n background-color: #18181b; /* zinc-900 */\n background-image:\n linear-gradient(45deg, #27272a 25%, transparent 25%),\n linear-gradient(-45deg, #27272a 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #27272a 75%),\n linear-gradient(-45deg, transparent 75%, #27272a 75%);\n}\n\n@keyframes fancy-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-slide-left {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-right {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n.fancy-fade-in {\n animation: fancy-fade-in 0.2s ease-out;\n}\n\n.fancy-slide-left {\n animation: fancy-slide-left 0.3s ease-out;\n}\n\n.fancy-slide-right {\n animation: fancy-slide-right 0.3s ease-out;\n}\n\n/* Overlay / floating animations */\n\n@keyframes fancy-scale-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes fancy-slide-up {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes fancy-fade-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n\n@keyframes fancy-toast-in {\n from {\n opacity: 0;\n transform: translateX(100%);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-collapse-open {\n from {\n grid-template-rows: 0fr;\n }\n to {\n grid-template-rows: 1fr;\n }\n}\n\n@keyframes fancy-collapse-close {\n from {\n grid-template-rows: 1fr;\n }\n to {\n grid-template-rows: 0fr;\n }\n}\n\n.fancy-scale-in {\n animation: fancy-scale-in 0.15s ease-out;\n}\n\n.fancy-slide-up {\n animation: fancy-slide-up 0.2s ease-out;\n}\n\n.fancy-fade-out {\n animation: fancy-fade-out 0.15s ease-in forwards;\n}\n\n.fancy-toast-in {\n animation: fancy-toast-in 0.3s ease-out;\n}\n\n.fancy-collapse-open {\n animation: fancy-collapse-open 0.2s ease-out forwards;\n}\n\n.fancy-collapse-close {\n animation: fancy-collapse-close 0.15s ease-in forwards;\n}\n\n/* Mobile flyout slide animations */\n\n@keyframes fancy-slide-in-left {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n@keyframes fancy-slide-out-left {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(-100%);\n }\n}\n\n@keyframes fancy-slide-in-right {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n\n/* Avatar glow — a looping halo ring (box-shadow only, no reflow). Color comes\n from the --fancy-glow custom property set on the element. */\n@keyframes fancy-avatar-glow {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 55%, transparent);\n opacity: 0.9;\n }\n 70% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.5;\n }\n 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 0%, transparent);\n opacity: 0.9;\n }\n}\n\n.fancy-avatar-glow {\n position: absolute;\n inset: 0;\n border-radius: 9999px;\n pointer-events: none;\n box-shadow:\n 0 0 0 2px color-mix(in srgb, var(--fancy-glow, #a855f7) 70%, transparent),\n 0 0 10px 0 color-mix(in srgb, var(--fancy-glow, #a855f7) 45%, transparent);\n animation: fancy-avatar-glow 1.6s ease-out infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .fancy-avatar-glow {\n animation: none;\n }\n}\n\n@keyframes fancy-slide-out-right {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n.fancy-slide-in-left {\n animation: fancy-slide-in-left 0.25s ease-out;\n}\n\n.fancy-slide-out-left {\n animation: fancy-slide-out-left 0.2s ease-in forwards;\n}\n\n.fancy-slide-in-right {\n animation: fancy-slide-in-right 0.25s ease-out;\n}\n\n.fancy-slide-out-right {\n animation: fancy-slide-out-right 0.2s ease-in forwards;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ # AudioViewer
2
+
3
+ A standalone audio viewer — a themed card wrapping the native audio player, with
4
+ an optional title. Renders for audio sources inside `MediaViewer`.
5
+
6
+ ## Import
7
+
8
+ ```tsx
9
+ import { AudioViewer } from "@particle-academy/react-fancy";
10
+ ```
11
+
12
+ ## Basic Usage
13
+
14
+ ```tsx
15
+ <AudioViewer src="/track.mp3" title="track.mp3" />
16
+ ```
17
+
18
+ ## Props
19
+
20
+ | Prop | Type | Default | Description |
21
+ |------|------|---------|-------------|
22
+ | src | `string` | — | Audio source (`http(s):` / `data:` / `blob:`) |
23
+ | title | `string` | — | Label shown above the player (e.g. the file name) |
24
+ | controls | `boolean` | `true` | Show native playback controls |
25
+ | autoPlay | `boolean` | `false` | Autoplay on mount |
26
+ | loop | `boolean` | `false` | Loop playback |
27
+ | onError | `() => void` | — | Fired when the audio fails to load |
28
+ | className | `string` | — | Classes for the card |
29
+ | style | `CSSProperties` | — | Styles for the card |
@@ -0,0 +1,60 @@
1
+ # ImageViewer
2
+
3
+ A standalone image viewer: fits the image to its container, with optional
4
+ Ctrl/⌘+wheel zoom, click-drag panning, and a transparency checkerboard. Works
5
+ anywhere on its own and is what `MediaViewer` renders for images (SVG included).
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { ImageViewer } from "@particle-academy/react-fancy";
11
+ ```
12
+
13
+ ## Basic Usage
14
+
15
+ ```tsx
16
+ <ImageViewer src="/logo.png" alt="logo.png" style={{ height: 320 }} />
17
+ ```
18
+
19
+ Give the container a height (via `style` or `className`) — it fills its box.
20
+
21
+ ## Props
22
+
23
+ | Prop | Type | Default | Description |
24
+ |------|------|---------|-------------|
25
+ | src | `string` | — | Image source (`http(s):` / `data:` / `blob:`) |
26
+ | alt | `string` | `""` | Alt text (also the download filename hint) |
27
+ | fit | `"contain" \| "cover" \| "none"` | `"contain"` | How the image sits at zoom 1 |
28
+ | zoomable | `boolean` | `true` | Ctrl/⌘+wheel zoom + zoom controls |
29
+ | pannable | `boolean` | `true` | Click-drag panning |
30
+ | controls | `boolean` | = `zoomable` | Show the floating zoom controls |
31
+ | minZoom | `number` | `0.25` | Minimum zoom factor |
32
+ | maxZoom | `number` | `8` | Maximum zoom factor |
33
+ | checkerboard | `boolean` | `true` | Paint a checkerboard behind the image |
34
+ | viewport | `{ panX; panY; zoom }` | — | Controlled pan + zoom |
35
+ | defaultViewport | `{ panX; panY; zoom }` | `{0,0,1}` | Initial viewport (uncontrolled) |
36
+ | onViewportChange | `(vp) => void` | — | Called whenever pan/zoom changes |
37
+ | onLoad | `() => void` | — | Image finished loading |
38
+ | onError | `() => void` | — | Image failed to load |
39
+ | className | `string` | — | Classes for the viewport container |
40
+ | style | `CSSProperties` | — | Styles for the container (e.g. a height) |
41
+
42
+ ## Human+ notes
43
+
44
+ The viewport is controllable (`viewport` + `onViewportChange`) so an agent
45
+ bridge can pan/zoom the image to point at something. Double-click resets zoom.
46
+
47
+ ## Examples
48
+
49
+ ### Static, non-interactive
50
+
51
+ ```tsx
52
+ <ImageViewer src="/thumb.jpg" zoomable={false} pannable={false} checkerboard={false} />
53
+ ```
54
+
55
+ ### Controlled viewport
56
+
57
+ ```tsx
58
+ const [vp, setVp] = useState({ panX: 0, panY: 0, zoom: 1 });
59
+ <ImageViewer src="/diagram.png" viewport={vp} onViewportChange={setVp} />
60
+ ```
@@ -0,0 +1,75 @@
1
+ # MediaViewer
2
+
3
+ Renders the right viewer for a media file — image, video, audio, or PDF — picked
4
+ from its MIME type (preferred) or its source URL, with a download fallback for
5
+ anything else. The single entry point for showing a file from a tree/workspace
6
+ when you don't know its type ahead of time. SVG renders through `ImageViewer`.
7
+
8
+ ## Import
9
+
10
+ ```tsx
11
+ import { MediaViewer } from "@particle-academy/react-fancy";
12
+ ```
13
+
14
+ ## Basic Usage
15
+
16
+ ```tsx
17
+ <MediaViewer src={url} mime="image/png" alt="logo.png" style={{ height: 320 }} />
18
+ ```
19
+
20
+ `mime` is preferred for picking the viewer. When omitted, the kind is sniffed
21
+ from `src` — a file extension, or the type embedded in a `data:` URI. Always
22
+ pass `mime` alongside a bare `blob:` URL, which carries no type of its own.
23
+
24
+ ## Props
25
+
26
+ | Prop | Type | Default | Description |
27
+ |------|------|---------|-------------|
28
+ | src | `string` | — | Media source (`http(s):` / `data:` / `blob:`) |
29
+ | mime | `string` | — | MIME type — preferred for picking the viewer |
30
+ | alt | `string` | — | Alt text / label (image alt, audio + PDF title) |
31
+ | kind | `"image" \| "video" \| "audio" \| "pdf" \| "unknown"` | — | Force a viewer, bypassing detection |
32
+ | imageProps | `Partial<ImageViewerProps>` | — | Extra props for the underlying `ImageViewer` |
33
+ | videoProps | `Partial<VideoViewerProps>` | — | Extra props for the underlying `VideoViewer` |
34
+ | audioProps | `Partial<AudioViewerProps>` | — | Extra props for the underlying `AudioViewer` |
35
+ | pdfProps | `Partial<PdfViewerProps>` | — | Extra props for the underlying `PdfViewer` |
36
+ | fallback | `ReactNode` | download card | Rendered for unknown / unpreviewable types |
37
+ | onError | `() => void` | — | Fired when the chosen viewer reports a load error |
38
+ | className | `string` | — | Forwarded to the chosen viewer |
39
+ | style | `CSSProperties` | — | Forwarded to the chosen viewer |
40
+
41
+ ## `resolveMediaType()`
42
+
43
+ The same detection logic, exported standalone so callers can branch their own
44
+ chrome (tabs, save buttons, …) — this is how `@particle-academy/fancy-code`'s
45
+ `FileViewer` decides text-vs-media.
46
+
47
+ ```tsx
48
+ import { resolveMediaType, type MediaKind } from "@particle-academy/react-fancy";
49
+
50
+ resolveMediaType({ mime: "image/png" }); // "image"
51
+ resolveMediaType({ src: "/clip.webm" }); // "video"
52
+ resolveMediaType({ src: "data:application/pdf,…" });// "pdf"
53
+ resolveMediaType({ src: "main.ts" }); // "unknown" → treat as text
54
+ ```
55
+
56
+ MIME wins when conclusive; otherwise `src` is sniffed (a `data:` URI's embedded
57
+ type first, then the file extension). Returns `"unknown"` when nothing matches.
58
+
59
+ ## Examples
60
+
61
+ ### Forwarding props to the underlying viewer
62
+
63
+ ```tsx
64
+ <MediaViewer
65
+ src={url}
66
+ mime="image/png"
67
+ imageProps={{ zoomable: false, checkerboard: false }}
68
+ />
69
+ ```
70
+
71
+ ### Custom fallback
72
+
73
+ ```tsx
74
+ <MediaViewer src={url} mime="application/zip" fallback={<MyDownloadCard url={url} />} />
75
+ ```
@@ -0,0 +1,29 @@
1
+ # PdfViewer
2
+
3
+ A standalone PDF viewer — embeds the document via the browser's native PDF
4
+ plugin (`<object>`), falling back to an `<iframe>`, then to a download link.
5
+ Renders for PDF sources inside `MediaViewer`.
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { PdfViewer } from "@particle-academy/react-fancy";
11
+ ```
12
+
13
+ ## Basic Usage
14
+
15
+ ```tsx
16
+ <PdfViewer src="/report.pdf" title="report.pdf" style={{ height: 600 }} />
17
+ ```
18
+
19
+ The viewer fills its container, so give it a height. A `min-h` floor (`20rem`)
20
+ is built in so it stays usable even without an explicit height.
21
+
22
+ ## Props
23
+
24
+ | Prop | Type | Default | Description |
25
+ |------|------|---------|-------------|
26
+ | src | `string` | — | PDF source (`http(s):` / `data:` / `blob:`) |
27
+ | title | `string` | `"PDF document"` | Accessible title for the embedded document |
28
+ | className | `string` | — | Classes for the container |
29
+ | style | `CSSProperties` | — | Styles for the container (e.g. a height) |
@@ -0,0 +1,31 @@
1
+ # VideoViewer
2
+
3
+ A standalone video viewer — native controls, optional poster, fit-to-box, and
4
+ dark-aware framing. Renders for video sources inside `MediaViewer`.
5
+
6
+ ## Import
7
+
8
+ ```tsx
9
+ import { VideoViewer } from "@particle-academy/react-fancy";
10
+ ```
11
+
12
+ ## Basic Usage
13
+
14
+ ```tsx
15
+ <VideoViewer src="/clip.mp4" poster="/clip.jpg" style={{ height: 360 }} />
16
+ ```
17
+
18
+ ## Props
19
+
20
+ | Prop | Type | Default | Description |
21
+ |------|------|---------|-------------|
22
+ | src | `string` | — | Video source (`http(s):` / `data:` / `blob:`) |
23
+ | poster | `string` | — | Poster image shown before playback |
24
+ | controls | `boolean` | `true` | Show native playback controls |
25
+ | autoPlay | `boolean` | `false` | Autoplay on mount (usually needs `muted`) |
26
+ | loop | `boolean` | `false` | Loop playback |
27
+ | muted | `boolean` | `false` | Start muted |
28
+ | fit | `"contain" \| "cover"` | `"contain"` | How the video fits its box |
29
+ | onError | `() => void` | — | Fired when the video fails to load |
30
+ | className | `string` | — | Classes for the container |
31
+ | style | `CSSProperties` | — | Styles for the container (e.g. a height) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "4.8.1",
3
+ "version": "4.9.0",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",