barua-ui 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/components/media.css +28 -0
- package/css/utilities.css +89 -0
- package/dist/index.cjs +118 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -3
- package/dist/index.d.ts +73 -3
- package/dist/index.js +115 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/css/components/media.css
CHANGED
|
@@ -232,6 +232,34 @@
|
|
|
232
232
|
opacity: 0;
|
|
233
233
|
transition: opacity var(--b-duration-slow) var(--b-ease-out);
|
|
234
234
|
}
|
|
235
|
+
/* ---- Blur-up ------------------------------------------------------------
|
|
236
|
+
*
|
|
237
|
+
* A shimmer says "something is coming". A blurred copy of the actual picture
|
|
238
|
+
* says "this is what is coming", which is a different and better promise —
|
|
239
|
+
* the layout is right, the colours are right, and the photograph resolves
|
|
240
|
+
* rather than appearing.
|
|
241
|
+
*
|
|
242
|
+
* The placeholder is a thumbnail small enough to inline: a 32px-wide JPEG is
|
|
243
|
+
* around a kilobyte, so it costs nothing and arrives with the markup. Give
|
|
244
|
+
* it as a data URI on --b-img-placeholder and mark the host with
|
|
245
|
+
* data-placeholder, which is what tells the shimmer to stand down.
|
|
246
|
+
*/
|
|
247
|
+
.b-async-img[data-placeholder]::before { display: none; }
|
|
248
|
+
|
|
249
|
+
.b-async-img[data-placeholder]::after {
|
|
250
|
+
content: "";
|
|
251
|
+
position: absolute;
|
|
252
|
+
inset: 0;
|
|
253
|
+
background: var(--b-img-placeholder) center / cover no-repeat;
|
|
254
|
+
/* Scaled up because a blur samples past the edges and would otherwise
|
|
255
|
+
leave a soft border all the way round. */
|
|
256
|
+
filter: blur(14px);
|
|
257
|
+
transform: scale(1.1);
|
|
258
|
+
transition: opacity var(--b-duration-slow) var(--b-ease-out);
|
|
259
|
+
pointer-events: none;
|
|
260
|
+
}
|
|
261
|
+
.b-async-img[data-placeholder].is-loaded::after { opacity: 0; }
|
|
262
|
+
|
|
235
263
|
.b-async-img.is-loaded::before { display: none; }
|
|
236
264
|
.b-async-img.is-loaded img { opacity: 1; }
|
|
237
265
|
|
package/css/utilities.css
CHANGED
|
@@ -470,12 +470,101 @@
|
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
/* ---- Symbol effects (SF Symbols bounce / pulse) -------------------------- */
|
|
473
|
+
/*
|
|
474
|
+
* The roster SF Symbols established, because a glyph that answers a press is
|
|
475
|
+
* the cheapest feedback an interface has. Each is one-shot unless it is
|
|
476
|
+
* describing an ongoing state — bounce acknowledges, breathe waits.
|
|
477
|
+
* prefers-reduced-motion is handled once, globally, in base.css.
|
|
478
|
+
*/
|
|
473
479
|
.b-icon--bounce svg, .b-icon--bounce { animation: b-icon-bounce 0.5s var(--b-ease-bounce); }
|
|
474
480
|
.b-icon--pulse svg, .b-icon--pulse { animation: b-pulse 1.6s var(--b-ease-standard) infinite; }
|
|
481
|
+
.b-icon--scale svg, .b-icon--scale { animation: b-icon-scale 0.32s var(--b-ease-standard); }
|
|
482
|
+
.b-icon--wiggle svg, .b-icon--wiggle { animation: b-icon-wiggle 0.5s var(--b-ease-standard); }
|
|
483
|
+
.b-icon--rotate svg, .b-icon--rotate { animation: b-icon-rotate 1.1s linear infinite; }
|
|
484
|
+
.b-icon--breathe svg, .b-icon--breathe { animation: b-icon-breathe 3s var(--b-ease-standard) infinite; }
|
|
485
|
+
.b-icon--replace svg, .b-icon--replace { animation: b-icon-replace 0.3s var(--b-ease-standard); }
|
|
486
|
+
|
|
475
487
|
@keyframes b-icon-bounce {
|
|
476
488
|
30% { translate: 0 -3px; scale: 1.15; }
|
|
477
489
|
60% { translate: 0 1px; scale: 0.96; }
|
|
478
490
|
}
|
|
491
|
+
@keyframes b-icon-scale {
|
|
492
|
+
50% { scale: 1.18; }
|
|
493
|
+
}
|
|
494
|
+
/* Small angles: a glyph that swings far reads as broken rather than lively. */
|
|
495
|
+
@keyframes b-icon-wiggle {
|
|
496
|
+
20% { rotate: -7deg; }
|
|
497
|
+
45% { rotate: 6deg; }
|
|
498
|
+
70% { rotate: -3deg; }
|
|
499
|
+
}
|
|
500
|
+
@keyframes b-icon-rotate {
|
|
501
|
+
to { rotate: 360deg; }
|
|
502
|
+
}
|
|
503
|
+
@keyframes b-icon-breathe {
|
|
504
|
+
50% { scale: 1.06; opacity: 0.75; }
|
|
505
|
+
}
|
|
506
|
+
/* The swap SwiftUI does between two glyphs: the old one leaves, the new
|
|
507
|
+
arrives. Put the class on the icon at the moment its `name` changes. */
|
|
508
|
+
@keyframes b-icon-replace {
|
|
509
|
+
0% { scale: 0.6; opacity: 0; }
|
|
510
|
+
100% { scale: 1; opacity: 1; }
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* ---- Scroll-driven reveal ------------------------------------------------
|
|
514
|
+
*
|
|
515
|
+
* The browser drives this from the element's own position in the scrollport,
|
|
516
|
+
* so there is no observer, no scroll listener and no main-thread work: the
|
|
517
|
+
* animation is tied to a timeline rather than to time.
|
|
518
|
+
*
|
|
519
|
+
* Everything stays visible where the timeline is unsupported. An entrance
|
|
520
|
+
* animation that fails closed hides the page. */
|
|
521
|
+
@supports (animation-timeline: view()) {
|
|
522
|
+
.b-reveal {
|
|
523
|
+
animation: b-reveal-in linear both;
|
|
524
|
+
animation-timeline: view();
|
|
525
|
+
/* Finish while the element is still coming up the screen, rather than
|
|
526
|
+
when it is centred — otherwise a reader watches it fade in. */
|
|
527
|
+
animation-range: entry 10% cover 32%;
|
|
528
|
+
}
|
|
529
|
+
.b-reveal--fade { animation-name: b-reveal-fade; }
|
|
530
|
+
.b-reveal--scale { animation-name: b-reveal-scale; }
|
|
531
|
+
.b-reveal--start { animation-name: b-reveal-start; }
|
|
532
|
+
.b-reveal--end { animation-name: b-reveal-end; }
|
|
533
|
+
}
|
|
534
|
+
@keyframes b-reveal-in {
|
|
535
|
+
from { opacity: 0; translate: 0 1.5rem; }
|
|
536
|
+
to { opacity: 1; translate: 0 0; }
|
|
537
|
+
}
|
|
538
|
+
@keyframes b-reveal-fade {
|
|
539
|
+
from { opacity: 0; }
|
|
540
|
+
to { opacity: 1; }
|
|
541
|
+
}
|
|
542
|
+
@keyframes b-reveal-scale {
|
|
543
|
+
from { opacity: 0; scale: 0.94; }
|
|
544
|
+
to { opacity: 1; scale: 1; }
|
|
545
|
+
}
|
|
546
|
+
@keyframes b-reveal-start {
|
|
547
|
+
from { opacity: 0; translate: -1.5rem 0; }
|
|
548
|
+
to { opacity: 1; translate: 0 0; }
|
|
549
|
+
}
|
|
550
|
+
@keyframes b-reveal-end {
|
|
551
|
+
from { opacity: 0; translate: 1.5rem 0; }
|
|
552
|
+
to { opacity: 1; translate: 0 0; }
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/* ---- Text that shrinks to fit its container -----------------------------
|
|
556
|
+
*
|
|
557
|
+
* SwiftUI's minimumScaleFactor has no CSS equivalent, but a container query
|
|
558
|
+
* unit does the same job honestly: the size is a fraction of the container's
|
|
559
|
+
* width, clamped so it never becomes unreadable or absurd. Needs a container
|
|
560
|
+
* ancestor — .b-fit-text establishes its own. */
|
|
561
|
+
.b-fit-text {
|
|
562
|
+
container-type: inline-size;
|
|
563
|
+
}
|
|
564
|
+
.b-fit-text > * {
|
|
565
|
+
font-size: clamp(var(--b-fit-min, 0.85rem), var(--b-fit-scale, 9cqi), var(--b-fit-max, 3rem));
|
|
566
|
+
white-space: nowrap;
|
|
567
|
+
}
|
|
479
568
|
|
|
480
569
|
/* ---- Safe area (mobile) ------------------------------------------------ */
|
|
481
570
|
.b-safe-area {
|
package/dist/index.cjs
CHANGED
|
@@ -97,6 +97,8 @@ __export(index_exports, {
|
|
|
97
97
|
CommandList: () => CommandList,
|
|
98
98
|
CommandPalette: () => CommandPalette,
|
|
99
99
|
Container: () => Container,
|
|
100
|
+
ContextMenuTarget: () => ContextMenuTarget,
|
|
101
|
+
CountUp: () => CountUp,
|
|
100
102
|
Dashboard: () => Dashboard,
|
|
101
103
|
DataGrid: () => DataGrid,
|
|
102
104
|
DatePicker: () => DatePicker,
|
|
@@ -127,6 +129,7 @@ __export(index_exports, {
|
|
|
127
129
|
FileTile: () => FileTile,
|
|
128
130
|
FilterBar: () => FilterBar,
|
|
129
131
|
FilterChip: () => FilterChip,
|
|
132
|
+
FitText: () => FitText,
|
|
130
133
|
Footnote: () => Footnote,
|
|
131
134
|
Footnotes: () => Footnotes,
|
|
132
135
|
Form: () => Form,
|
|
@@ -211,6 +214,7 @@ __export(index_exports, {
|
|
|
211
214
|
Resizable: () => Resizable,
|
|
212
215
|
ResizeHandle: () => ResizeHandle,
|
|
213
216
|
Result: () => Result,
|
|
217
|
+
Reveal: () => Reveal,
|
|
214
218
|
SafeArea: () => SafeArea,
|
|
215
219
|
ScatterChart: () => ScatterChart,
|
|
216
220
|
ScrollArea: () => ScrollArea,
|
|
@@ -2391,7 +2395,32 @@ var OnboardingFeature = (0, import_react19.forwardRef)(
|
|
|
2391
2395
|
var import_react20 = require("react");
|
|
2392
2396
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2393
2397
|
var MediaPlaceholder = block("div", "b-media-placeholder", "MediaPlaceholder");
|
|
2394
|
-
var AsyncImage =
|
|
2398
|
+
var AsyncImage = (0, import_react20.forwardRef)(function AsyncImage2({ src, alt, placeholder, aspect, className, style, ...rest }, ref) {
|
|
2399
|
+
const [loaded, setLoaded] = (0, import_react20.useState)(false);
|
|
2400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2401
|
+
"span",
|
|
2402
|
+
{
|
|
2403
|
+
className: cn("b-async-img", loaded && "is-loaded", className),
|
|
2404
|
+
"data-placeholder": placeholder ? "" : void 0,
|
|
2405
|
+
style: {
|
|
2406
|
+
...aspect ? { aspectRatio: aspect } : null,
|
|
2407
|
+
...placeholder ? { ["--b-img-placeholder"]: `url("${placeholder}")` } : null,
|
|
2408
|
+
...style
|
|
2409
|
+
},
|
|
2410
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2411
|
+
"img",
|
|
2412
|
+
{
|
|
2413
|
+
ref,
|
|
2414
|
+
src,
|
|
2415
|
+
alt,
|
|
2416
|
+
onLoad: () => setLoaded(true),
|
|
2417
|
+
onError: () => setLoaded(true),
|
|
2418
|
+
...rest
|
|
2419
|
+
}
|
|
2420
|
+
)
|
|
2421
|
+
}
|
|
2422
|
+
);
|
|
2423
|
+
});
|
|
2395
2424
|
var Web = block("div", "b-web", "Web");
|
|
2396
2425
|
var Video = block("video", "b-video", "Video");
|
|
2397
2426
|
var Audio = block("div", "b-audio", "Audio");
|
|
@@ -2466,6 +2495,90 @@ var CommandCenterTile = block("div", "b-cc__tile", "CommandCenterTile");
|
|
|
2466
2495
|
var CommandCenterLabel = block("div", "b-cc__label", "CommandCenterLabel");
|
|
2467
2496
|
var CommandCenterStatus = block("div", "b-cc__status", "CommandCenterStatus");
|
|
2468
2497
|
var ImageLens = block("div", "b-lens", "ImageLens");
|
|
2498
|
+
|
|
2499
|
+
// src/motion.tsx
|
|
2500
|
+
var import_react21 = require("react");
|
|
2501
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2502
|
+
var Reveal = (0, import_react21.forwardRef)(function Reveal2({ as: Tag2 = "div", variant = "up", className, children, ...rest }, ref) {
|
|
2503
|
+
const Component = Tag2;
|
|
2504
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2505
|
+
Component,
|
|
2506
|
+
{
|
|
2507
|
+
ref,
|
|
2508
|
+
className: cn("b-reveal", variant !== "up" && `b-reveal--${variant}`, className),
|
|
2509
|
+
...rest,
|
|
2510
|
+
children
|
|
2511
|
+
}
|
|
2512
|
+
);
|
|
2513
|
+
});
|
|
2514
|
+
var FitText = (0, import_react21.forwardRef)(function FitText2({ min, max, scale, className, style, children, ...rest }, ref) {
|
|
2515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2516
|
+
"div",
|
|
2517
|
+
{
|
|
2518
|
+
ref,
|
|
2519
|
+
className: cn("b-fit-text", className),
|
|
2520
|
+
style: {
|
|
2521
|
+
...min ? { ["--b-fit-min"]: min } : null,
|
|
2522
|
+
...max ? { ["--b-fit-max"]: max } : null,
|
|
2523
|
+
...scale ? { ["--b-fit-scale"]: scale } : null,
|
|
2524
|
+
...style
|
|
2525
|
+
},
|
|
2526
|
+
...rest,
|
|
2527
|
+
children
|
|
2528
|
+
}
|
|
2529
|
+
);
|
|
2530
|
+
});
|
|
2531
|
+
var CountUp = (0, import_react21.forwardRef)(function CountUp2({ to, decimals = 0, duration = 700, prefix = "", suffix = "", grouped = true, className, ...rest }, ref) {
|
|
2532
|
+
const node = (0, import_react21.useRef)(null);
|
|
2533
|
+
const from = (0, import_react21.useRef)(0);
|
|
2534
|
+
(0, import_react21.useEffect)(() => {
|
|
2535
|
+
const el = node.current;
|
|
2536
|
+
if (!el) return;
|
|
2537
|
+
const start = from.current;
|
|
2538
|
+
const target = to;
|
|
2539
|
+
from.current = to;
|
|
2540
|
+
const render = (value) => {
|
|
2541
|
+
const text = grouped ? value.toLocaleString(void 0, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }) : value.toFixed(decimals);
|
|
2542
|
+
el.textContent = `${prefix}${text}${suffix}`;
|
|
2543
|
+
};
|
|
2544
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
2545
|
+
render(target);
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
let frame = 0;
|
|
2549
|
+
const began = performance.now();
|
|
2550
|
+
const step = (now) => {
|
|
2551
|
+
const p = Math.min(1, (now - began) / duration);
|
|
2552
|
+
render(start + (target - start) * (1 - Math.pow(1 - p, 3)));
|
|
2553
|
+
if (p < 1) frame = requestAnimationFrame(step);
|
|
2554
|
+
};
|
|
2555
|
+
frame = requestAnimationFrame(step);
|
|
2556
|
+
return () => cancelAnimationFrame(frame);
|
|
2557
|
+
}, [to, decimals, duration, prefix, suffix, grouped]);
|
|
2558
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2559
|
+
"span",
|
|
2560
|
+
{
|
|
2561
|
+
ref: (el) => {
|
|
2562
|
+
node.current = el;
|
|
2563
|
+
if (typeof ref === "function") ref(el);
|
|
2564
|
+
else if (ref) ref.current = el;
|
|
2565
|
+
},
|
|
2566
|
+
className: cn("b-tabular-nums", className),
|
|
2567
|
+
...rest,
|
|
2568
|
+
children: [
|
|
2569
|
+
prefix,
|
|
2570
|
+
0 .toFixed(decimals),
|
|
2571
|
+
suffix
|
|
2572
|
+
]
|
|
2573
|
+
}
|
|
2574
|
+
);
|
|
2575
|
+
});
|
|
2576
|
+
var ContextMenuTarget = (0, import_react21.forwardRef)(
|
|
2577
|
+
function ContextMenuTarget2({ as: Tag2 = "div", menu, children, ...rest }, ref) {
|
|
2578
|
+
const Component = Tag2;
|
|
2579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Component, { ref, "data-b-contextmenu": menu, ...rest, children });
|
|
2580
|
+
}
|
|
2581
|
+
);
|
|
2469
2582
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2470
2583
|
0 && (module.exports = {
|
|
2471
2584
|
Accordion,
|
|
@@ -2544,6 +2657,8 @@ var ImageLens = block("div", "b-lens", "ImageLens");
|
|
|
2544
2657
|
CommandList,
|
|
2545
2658
|
CommandPalette,
|
|
2546
2659
|
Container,
|
|
2660
|
+
ContextMenuTarget,
|
|
2661
|
+
CountUp,
|
|
2547
2662
|
Dashboard,
|
|
2548
2663
|
DataGrid,
|
|
2549
2664
|
DatePicker,
|
|
@@ -2574,6 +2689,7 @@ var ImageLens = block("div", "b-lens", "ImageLens");
|
|
|
2574
2689
|
FileTile,
|
|
2575
2690
|
FilterBar,
|
|
2576
2691
|
FilterChip,
|
|
2692
|
+
FitText,
|
|
2577
2693
|
Footnote,
|
|
2578
2694
|
Footnotes,
|
|
2579
2695
|
Form,
|
|
@@ -2658,6 +2774,7 @@ var ImageLens = block("div", "b-lens", "ImageLens");
|
|
|
2658
2774
|
Resizable,
|
|
2659
2775
|
ResizeHandle,
|
|
2660
2776
|
Result,
|
|
2777
|
+
Reveal,
|
|
2661
2778
|
SafeArea,
|
|
2662
2779
|
ScatterChart,
|
|
2663
2780
|
ScrollArea,
|