@olwiba/ui 0.2.12 → 0.2.14
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.d.ts +83 -55
- package/dist/index.js +33 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AuthSection.tsx +35 -2
- package/src/components/PricingCard.tsx +18 -3
- package/src/marketing/PricingSection.tsx +10 -1
package/dist/index.d.ts
CHANGED
|
@@ -335,9 +335,21 @@ interface AuthSectionProps extends AuthFormProps {
|
|
|
335
335
|
children?: React.ReactNode;
|
|
336
336
|
/** (split layout only) Custom content for the left decorative panel */
|
|
337
337
|
panel?: React.ReactNode;
|
|
338
|
+
/**
|
|
339
|
+
* Render inside an existing page frame — one already providing the
|
|
340
|
+
* background, the horizontal padding, and a navbar and footer.
|
|
341
|
+
*
|
|
342
|
+
* Standalone (the default) the section owns the whole viewport, which is
|
|
343
|
+
* right for an auth screen that is the only thing on the page. It is wrong
|
|
344
|
+
* the moment there is chrome around it: the padding lands on top of the
|
|
345
|
+
* frame's own, and `min-h-dvh` guarantees the footer starts below the fold.
|
|
346
|
+
*
|
|
347
|
+
* (centered layout only)
|
|
348
|
+
*/
|
|
349
|
+
framed?: boolean;
|
|
338
350
|
className?: string;
|
|
339
351
|
}
|
|
340
|
-
declare function AuthSection({ layout, children, panel, className, ...formProps }: AuthSectionProps): react_jsx_runtime.JSX.Element;
|
|
352
|
+
declare function AuthSection({ layout, children, panel, framed, className, ...formProps }: AuthSectionProps): react_jsx_runtime.JSX.Element;
|
|
341
353
|
|
|
342
354
|
interface SettingsSectionProps {
|
|
343
355
|
title: string;
|
|
@@ -681,6 +693,58 @@ interface CtaSectionProps {
|
|
|
681
693
|
}
|
|
682
694
|
declare function CtaSection(props: CtaSectionProps): react_jsx_runtime.JSX.Element;
|
|
683
695
|
|
|
696
|
+
/**
|
|
697
|
+
* A transition is pure data: two layers, each with a start and an end style.
|
|
698
|
+
* Adding an effect means adding an entry to {@link EFFECTS} — the component
|
|
699
|
+
* itself never learns what "roll" means. Consumers can pass a spec object
|
|
700
|
+
* directly for anything not in the set.
|
|
701
|
+
*/
|
|
702
|
+
interface AnimatedSwapSpec {
|
|
703
|
+
/** Hide overflow on the container. Required by effects that travel further than they fade. */
|
|
704
|
+
clip: boolean;
|
|
705
|
+
duration: number;
|
|
706
|
+
easing: string;
|
|
707
|
+
/** The incoming layer: where it starts, where it lands. */
|
|
708
|
+
enter: {
|
|
709
|
+
from: React.CSSProperties;
|
|
710
|
+
to: React.CSSProperties;
|
|
711
|
+
};
|
|
712
|
+
/** The outgoing layer: where it starts, where it leaves. */
|
|
713
|
+
exit: {
|
|
714
|
+
from: React.CSSProperties;
|
|
715
|
+
to: React.CSSProperties;
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
type AnimatedSwapEffect = 'roll' | 'fade' | 'slide' | 'none';
|
|
719
|
+
interface AnimatedSwapProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
720
|
+
/**
|
|
721
|
+
* Changing this is the swap. Nothing else triggers one — the component
|
|
722
|
+
* can't see inside `children`, so re-rendering with different content under
|
|
723
|
+
* the same key updates in place with no animation.
|
|
724
|
+
*/
|
|
725
|
+
swapKey: React.Key;
|
|
726
|
+
/** Named effect, or a spec of your own. Defaults from the current UI mode. */
|
|
727
|
+
effect?: AnimatedSwapEffect | AnimatedSwapSpec;
|
|
728
|
+
/** Override the effect's duration, in ms. */
|
|
729
|
+
duration?: number;
|
|
730
|
+
children: React.ReactNode;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Animates the replacement of arbitrary content when `swapKey` changes: a
|
|
734
|
+
* price when the billing cadence toggles, a chart when the range changes, a
|
|
735
|
+
* status pill when a job finishes.
|
|
736
|
+
*
|
|
737
|
+
* Both versions are mounted for the length of the transition. The incoming
|
|
738
|
+
* one stays in normal flow so the container sizes to it immediately; the
|
|
739
|
+
* outgoing one is lifted out of flow and overlaid, so content below settles
|
|
740
|
+
* once, at the start, under cover of the animation — rather than snapping
|
|
741
|
+
* when the old copy unmounts.
|
|
742
|
+
*
|
|
743
|
+
* CSS transitions only: no keyframes to register in a consumer's Tailwind
|
|
744
|
+
* config, and no motion library.
|
|
745
|
+
*/
|
|
746
|
+
declare function AnimatedSwap({ swapKey, effect, duration, children, className, style, ...props }: AnimatedSwapProps): react_jsx_runtime.JSX.Element;
|
|
747
|
+
|
|
684
748
|
interface PricingFeature {
|
|
685
749
|
label: string;
|
|
686
750
|
included: boolean;
|
|
@@ -699,9 +763,18 @@ interface PricingCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
699
763
|
badge?: React.ReactNode;
|
|
700
764
|
/** Rendered directly below the CTA button (e.g. a "Get notified" link). */
|
|
701
765
|
footer?: React.ReactNode;
|
|
766
|
+
/**
|
|
767
|
+
* How the price transitions when a cadence toggle swaps it. Omit and the
|
|
768
|
+
* current UI mode decides — `fade` in default, `roll` in playful, `slide` in
|
|
769
|
+
* smooth — which is the right answer for a product that has picked a mode
|
|
770
|
+
* and wants every swap on the page to agree with it. Set it when the price
|
|
771
|
+
* specifically should read as a mechanism (`'roll'`) without moving the
|
|
772
|
+
* whole app to playful.
|
|
773
|
+
*/
|
|
774
|
+
priceEffect?: AnimatedSwapEffect | AnimatedSwapSpec;
|
|
702
775
|
onSelect?: () => void;
|
|
703
776
|
}
|
|
704
|
-
declare function PricingCard({ name, price, period, description, features, cta, highlighted, disabled, ctaDisabled, badge, footer, onSelect, className, ...props }: PricingCardProps): react_jsx_runtime.JSX.Element;
|
|
777
|
+
declare function PricingCard({ name, price, period, description, features, cta, highlighted, disabled, ctaDisabled, badge, footer, priceEffect, onSelect, className, ...props }: PricingCardProps): react_jsx_runtime.JSX.Element;
|
|
705
778
|
|
|
706
779
|
/**
|
|
707
780
|
* One billing period a plan can be bought at.
|
|
@@ -779,8 +852,15 @@ interface PricingSectionProps {
|
|
|
779
852
|
onSelectPlan?: (plan: PricingPlan, cadence?: string) => void;
|
|
780
853
|
/** Marks one plan as busy (e.g. its checkout is being created). */
|
|
781
854
|
pendingPlanName?: string;
|
|
855
|
+
/**
|
|
856
|
+
* How each card's price transitions when the cadence toggle changes it.
|
|
857
|
+
* Omit and the current UI mode decides (see `PricingCard.priceEffect`) —
|
|
858
|
+
* pass `'roll'` for an odometer on a product that is otherwise in default
|
|
859
|
+
* mode.
|
|
860
|
+
*/
|
|
861
|
+
priceEffect?: PricingCardProps['priceEffect'];
|
|
782
862
|
}
|
|
783
|
-
declare function PricingSection({ title, description, badge, plans, saveBadge, isAuthenticated, renderLink, footnote, mode, foundingDeadline, currency, highlightedBadgeLabel, renderPlanFooter, cadences, defaultCadence, onSelectPlan, pendingPlanName, }: PricingSectionProps): react_jsx_runtime.JSX.Element;
|
|
863
|
+
declare function PricingSection({ title, description, badge, plans, saveBadge, isAuthenticated, renderLink, footnote, mode, foundingDeadline, currency, highlightedBadgeLabel, renderPlanFooter, cadences, defaultCadence, onSelectPlan, pendingPlanName, priceEffect, }: PricingSectionProps): react_jsx_runtime.JSX.Element;
|
|
784
864
|
|
|
785
865
|
interface TestimonialsSectionProps {
|
|
786
866
|
title?: string;
|
|
@@ -1039,58 +1119,6 @@ interface CountUpProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
1039
1119
|
}
|
|
1040
1120
|
declare function CountUp({ from, to, duration, decimals, prefix, suffix, once, className, ...props }: CountUpProps): react_jsx_runtime.JSX.Element;
|
|
1041
1121
|
|
|
1042
|
-
/**
|
|
1043
|
-
* A transition is pure data: two layers, each with a start and an end style.
|
|
1044
|
-
* Adding an effect means adding an entry to {@link EFFECTS} — the component
|
|
1045
|
-
* itself never learns what "roll" means. Consumers can pass a spec object
|
|
1046
|
-
* directly for anything not in the set.
|
|
1047
|
-
*/
|
|
1048
|
-
interface AnimatedSwapSpec {
|
|
1049
|
-
/** Hide overflow on the container. Required by effects that travel further than they fade. */
|
|
1050
|
-
clip: boolean;
|
|
1051
|
-
duration: number;
|
|
1052
|
-
easing: string;
|
|
1053
|
-
/** The incoming layer: where it starts, where it lands. */
|
|
1054
|
-
enter: {
|
|
1055
|
-
from: React.CSSProperties;
|
|
1056
|
-
to: React.CSSProperties;
|
|
1057
|
-
};
|
|
1058
|
-
/** The outgoing layer: where it starts, where it leaves. */
|
|
1059
|
-
exit: {
|
|
1060
|
-
from: React.CSSProperties;
|
|
1061
|
-
to: React.CSSProperties;
|
|
1062
|
-
};
|
|
1063
|
-
}
|
|
1064
|
-
type AnimatedSwapEffect = 'roll' | 'fade' | 'slide' | 'none';
|
|
1065
|
-
interface AnimatedSwapProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
1066
|
-
/**
|
|
1067
|
-
* Changing this is the swap. Nothing else triggers one — the component
|
|
1068
|
-
* can't see inside `children`, so re-rendering with different content under
|
|
1069
|
-
* the same key updates in place with no animation.
|
|
1070
|
-
*/
|
|
1071
|
-
swapKey: React.Key;
|
|
1072
|
-
/** Named effect, or a spec of your own. Defaults from the current UI mode. */
|
|
1073
|
-
effect?: AnimatedSwapEffect | AnimatedSwapSpec;
|
|
1074
|
-
/** Override the effect's duration, in ms. */
|
|
1075
|
-
duration?: number;
|
|
1076
|
-
children: React.ReactNode;
|
|
1077
|
-
}
|
|
1078
|
-
/**
|
|
1079
|
-
* Animates the replacement of arbitrary content when `swapKey` changes: a
|
|
1080
|
-
* price when the billing cadence toggles, a chart when the range changes, a
|
|
1081
|
-
* status pill when a job finishes.
|
|
1082
|
-
*
|
|
1083
|
-
* Both versions are mounted for the length of the transition. The incoming
|
|
1084
|
-
* one stays in normal flow so the container sizes to it immediately; the
|
|
1085
|
-
* outgoing one is lifted out of flow and overlaid, so content below settles
|
|
1086
|
-
* once, at the start, under cover of the animation — rather than snapping
|
|
1087
|
-
* when the old copy unmounts.
|
|
1088
|
-
*
|
|
1089
|
-
* CSS transitions only: no keyframes to register in a consumer's Tailwind
|
|
1090
|
-
* config, and no motion library.
|
|
1091
|
-
*/
|
|
1092
|
-
declare function AnimatedSwap({ swapKey, effect, duration, children, className, style, ...props }: AnimatedSwapProps): react_jsx_runtime.JSX.Element;
|
|
1093
|
-
|
|
1094
1122
|
interface CountdownTimerProps {
|
|
1095
1123
|
deadline: string;
|
|
1096
1124
|
label?: string;
|
package/dist/index.js
CHANGED
|
@@ -472,7 +472,24 @@ function AppShell({
|
|
|
472
472
|
return inner;
|
|
473
473
|
}
|
|
474
474
|
var defaultRenderLink2 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
475
|
-
function CenteredAuth({ children, brand, className }) {
|
|
475
|
+
function CenteredAuth({ children, brand, framed, className }) {
|
|
476
|
+
if (framed) {
|
|
477
|
+
return (
|
|
478
|
+
// Framed: a page frame is already supplying the background, the page
|
|
479
|
+
// padding, and — with a navbar and footer around it — the height. All
|
|
480
|
+
// three have to come off here or they are applied twice: padding inside
|
|
481
|
+
// padding, and a full-viewport section that pushes the footer below the
|
|
482
|
+
// fold on every auth screen.
|
|
483
|
+
//
|
|
484
|
+
// The card fills the content column on a phone, matching the contact
|
|
485
|
+
// form, and only takes its reading width once there is room for the
|
|
486
|
+
// page to centre it.
|
|
487
|
+
/* @__PURE__ */ jsx("section", { className: cn$1("flex flex-col py-6 sm:py-10", className), children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-none sm:my-auto sm:max-w-md", children: [
|
|
488
|
+
brand && /* @__PURE__ */ jsx("div", { className: "mb-8 text-center", children: brand }),
|
|
489
|
+
children
|
|
490
|
+
] }) })
|
|
491
|
+
);
|
|
492
|
+
}
|
|
476
493
|
return (
|
|
477
494
|
// `min-h-dvh`, not `min-h-screen`: on mobile `100vh` is the viewport with
|
|
478
495
|
// the browser chrome *retracted*, so a screen-height box is always taller
|
|
@@ -650,6 +667,7 @@ function AuthSection({
|
|
|
650
667
|
layout = "centered",
|
|
651
668
|
children,
|
|
652
669
|
panel,
|
|
670
|
+
framed,
|
|
653
671
|
className,
|
|
654
672
|
...formProps
|
|
655
673
|
}) {
|
|
@@ -659,7 +677,7 @@ function AuthSection({
|
|
|
659
677
|
}
|
|
660
678
|
const { brand, ...restFormProps } = formProps;
|
|
661
679
|
const form = children ?? /* @__PURE__ */ jsx(DefaultForm, { ...restFormProps });
|
|
662
|
-
return /* @__PURE__ */ jsx(CenteredAuth, { brand, className, children: form });
|
|
680
|
+
return /* @__PURE__ */ jsx(CenteredAuth, { brand, framed, className, children: form });
|
|
663
681
|
}
|
|
664
682
|
function SettingsSection({ title, description, children, danger = false, className }) {
|
|
665
683
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("grid grid-cols-1 gap-x-8 gap-y-6 py-10 sm:grid-cols-3", className), children: [
|
|
@@ -2291,6 +2309,7 @@ function PricingCard({
|
|
|
2291
2309
|
ctaDisabled = false,
|
|
2292
2310
|
badge,
|
|
2293
2311
|
footer,
|
|
2312
|
+
priceEffect,
|
|
2294
2313
|
onSelect,
|
|
2295
2314
|
className,
|
|
2296
2315
|
...props
|
|
@@ -2312,7 +2331,15 @@ function PricingCard({
|
|
|
2312
2331
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
2313
2332
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
|
|
2314
2333
|
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
|
|
2315
|
-
/* @__PURE__ */ jsx(
|
|
2334
|
+
/* @__PURE__ */ jsx(
|
|
2335
|
+
AnimatedSwap,
|
|
2336
|
+
{
|
|
2337
|
+
swapKey: price,
|
|
2338
|
+
effect: priceEffect,
|
|
2339
|
+
className: "text-4xl font-bold tracking-tight",
|
|
2340
|
+
children: price
|
|
2341
|
+
}
|
|
2342
|
+
),
|
|
2316
2343
|
/* @__PURE__ */ jsx("span", { className: "mb-1 text-sm text-muted-foreground", children: period })
|
|
2317
2344
|
] }),
|
|
2318
2345
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
|
|
@@ -2452,7 +2479,8 @@ function PricingSection({
|
|
|
2452
2479
|
cadences,
|
|
2453
2480
|
defaultCadence,
|
|
2454
2481
|
onSelectPlan,
|
|
2455
|
-
pendingPlanName
|
|
2482
|
+
pendingPlanName,
|
|
2483
|
+
priceEffect
|
|
2456
2484
|
}) {
|
|
2457
2485
|
const [annual, setAnnual] = React20.useState(false);
|
|
2458
2486
|
const isOneTime = mode === "one-time";
|
|
@@ -2549,6 +2577,7 @@ function PricingSection({
|
|
|
2549
2577
|
ctaDisabled: plan.ctaDisabled || pendingPlanName === plan.name,
|
|
2550
2578
|
badge: badge2,
|
|
2551
2579
|
footer: renderPlanFooter?.(plan),
|
|
2580
|
+
priceEffect,
|
|
2552
2581
|
onSelect: onSelectPlan ? () => onSelectPlan(plan, useCadences ? activeCadence : void 0) : void 0
|
|
2553
2582
|
},
|
|
2554
2583
|
plan.name
|