@orangecheck/app-design 0.3.2 → 0.4.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.
@@ -83,6 +83,131 @@ function Prose({ className, ...props }) {
83
83
  }
84
84
  );
85
85
  }
86
+ function prefersStill() {
87
+ return typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
88
+ }
89
+ function useInView(rootMargin = "0px 0px -12% 0px") {
90
+ const ref = react.useRef(null);
91
+ const [seen, setSeen] = react.useState(false);
92
+ react.useEffect(() => {
93
+ const el = ref.current;
94
+ if (!el || seen) return;
95
+ if (typeof IntersectionObserver === "undefined") {
96
+ setSeen(true);
97
+ return;
98
+ }
99
+ const io = new IntersectionObserver(
100
+ ([e]) => {
101
+ if (e?.isIntersecting) {
102
+ setSeen(true);
103
+ io.disconnect();
104
+ }
105
+ },
106
+ { rootMargin }
107
+ );
108
+ io.observe(el);
109
+ return () => io.disconnect();
110
+ }, [rootMargin, seen]);
111
+ return [ref, seen];
112
+ }
113
+ function Reveal({
114
+ as = "div",
115
+ delay = 0,
116
+ className,
117
+ style,
118
+ children
119
+ }) {
120
+ const ref = react.useRef(null);
121
+ react.useEffect(() => {
122
+ const el = ref.current;
123
+ if (!el || prefersStill() || typeof IntersectionObserver === "undefined") return;
124
+ if (el.getBoundingClientRect().top < window.innerHeight * 0.92) return;
125
+ el.dataset.reveal = "pending";
126
+ const io = new IntersectionObserver(
127
+ ([e]) => {
128
+ if (e?.isIntersecting) {
129
+ el.dataset.reveal = "shown";
130
+ io.disconnect();
131
+ }
132
+ },
133
+ { rootMargin: "0px 0px -10% 0px" }
134
+ );
135
+ io.observe(el);
136
+ return () => io.disconnect();
137
+ }, []);
138
+ return react.createElement(
139
+ as,
140
+ { ref, className, style: { ...style, "--reveal-delay": `${delay}ms` } },
141
+ children
142
+ );
143
+ }
144
+ function ScrollStory({
145
+ length = 2,
146
+ className,
147
+ innerClassName,
148
+ children
149
+ }) {
150
+ const ref = react.useRef(null);
151
+ const [pinned, setPinned] = react.useState(false);
152
+ react.useEffect(() => {
153
+ const el = ref.current;
154
+ if (!el || prefersStill()) return;
155
+ setPinned(true);
156
+ let raf = 0;
157
+ const update = () => {
158
+ raf = 0;
159
+ const r = el.getBoundingClientRect();
160
+ const travel = r.height - window.innerHeight;
161
+ const p = travel > 0 ? Math.min(1, Math.max(0, -r.top / travel)) : 0;
162
+ el.style.setProperty("--p", p.toFixed(4));
163
+ };
164
+ const on = () => {
165
+ if (!raf) raf = requestAnimationFrame(update);
166
+ };
167
+ update();
168
+ window.addEventListener("scroll", on, { passive: true });
169
+ window.addEventListener("resize", on);
170
+ return () => {
171
+ cancelAnimationFrame(raf);
172
+ window.removeEventListener("scroll", on);
173
+ window.removeEventListener("resize", on);
174
+ };
175
+ }, []);
176
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("relative", className), style: pinned ? { height: `${length * 100}svh` } : void 0, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(pinned && "sticky top-0 flex min-h-svh items-center", innerClassName), children }) });
177
+ }
178
+ function Ticker({
179
+ value,
180
+ duration = 1200,
181
+ format = (n) => Math.round(n).toLocaleString("en-US"),
182
+ className
183
+ }) {
184
+ const [ref, seen] = useInView();
185
+ const [shown, setShown] = react.useState(value);
186
+ const animate = react.useRef(null);
187
+ react.useEffect(() => {
188
+ const el = ref.current;
189
+ if (!el || animate.current !== null) return;
190
+ animate.current = !prefersStill() && el.getBoundingClientRect().top > window.innerHeight * 0.9;
191
+ if (animate.current) setShown(0);
192
+ }, [ref]);
193
+ react.useEffect(() => {
194
+ if (!seen) return;
195
+ if (!animate.current) {
196
+ setShown(value);
197
+ return;
198
+ }
199
+ let raf = 0;
200
+ const t0 = performance.now();
201
+ const step = (now) => {
202
+ const k = Math.min(1, (now - t0) / duration);
203
+ setShown(value * (1 - Math.pow(1 - k, 3)));
204
+ if (k < 1) raf = requestAnimationFrame(step);
205
+ };
206
+ raf = requestAnimationFrame(step);
207
+ return () => cancelAnimationFrame(raf);
208
+ }, [seen, value, duration]);
209
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: cn("oca-tabular", className), children: format(shown) });
210
+ }
86
211
  var sectionVariants = classVarianceAuthority.cva("relative w-full overflow-x-clip", {
87
212
  variants: {
88
213
  tone: {
@@ -111,19 +236,12 @@ function Container({ className, ...props }) {
111
236
  function SectionIntro({
112
237
  className,
113
238
  align = "start",
114
- ...props
239
+ reveal = true,
240
+ children,
241
+ style
115
242
  }) {
116
- return /* @__PURE__ */ jsxRuntime.jsx(
117
- "div",
118
- {
119
- className: cn(
120
- "flex flex-col gap-4 md:gap-5",
121
- align === "center" && "mx-auto items-center text-center",
122
- className
123
- ),
124
- ...props
125
- }
126
- );
243
+ const cls = cn("flex flex-col gap-4 md:gap-5", align === "center" && "mx-auto items-center text-center", className);
244
+ return reveal ? /* @__PURE__ */ jsxRuntime.jsx(Reveal, { className: cls, style, children }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cls, style, children });
127
245
  }
128
246
  function PageHero({
129
247
  eyebrow,
@@ -142,14 +260,14 @@ function PageHero({
142
260
  }
143
261
  return /* @__PURE__ */ jsxRuntime.jsx(Section, { space: "none", className: cn("pb-14 pt-12 md:pb-20 md:pt-20", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid grid-cols-1 gap-10", art && "items-center md:grid-cols-12"), children: [
144
262
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col items-start gap-6", art ? "md:col-span-7" : "max-w-[52rem]"), children: [
145
- eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
146
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: size === "xl" ? "oca-display-1" : "oca-display-2", children: title }),
147
- lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead max-w-[38rem]", children: lead }) : null,
148
- meta ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
149
- actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null,
150
- children
263
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow oca-enter", children: eyebrow }) : null,
264
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: cn(size === "xl" ? "oca-display-1" : "oca-display-2", "oca-enter [--enter-delay:70ms]"), children: title }),
265
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead oca-enter max-w-[38rem] [--enter-delay:150ms]", children: lead }) : null,
266
+ meta ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-enter text-[0.875rem] text-muted-foreground [--enter-delay:190ms]", children: meta }) : null,
267
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions }) : null,
268
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter w-full [--enter-delay:270ms]", children }) : null
151
269
  ] }),
152
- art ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-5", children: art }) : null
270
+ art ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter md:col-span-5 [--enter-delay:120ms]", children: art }) : null
153
271
  ] }) });
154
272
  }
155
273
  function DocHeader({
@@ -162,8 +280,8 @@ function DocHeader({
162
280
  className
163
281
  }) {
164
282
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
165
- eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
166
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
283
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow oca-enter", children: eyebrow }) : null,
284
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2 oca-enter [--enter-delay:70ms]", children: title }),
167
285
  lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null,
168
286
  meta ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
169
287
  actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex flex-wrap gap-3", children: actions }) : null,
@@ -1118,9 +1236,84 @@ function SatsFigure({
1118
1236
  hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1119
1237
  ] });
1120
1238
  }
1239
+ function PhoneFrame({ className, style, children }) {
1240
+ return /* @__PURE__ */ jsxRuntime.jsx(
1241
+ "div",
1242
+ {
1243
+ className: cn(
1244
+ "relative w-[17.5rem] shrink-0 rounded-[2.9rem] bg-[#0b0b0c] p-[0.6rem]",
1245
+ "shadow-[0_50px_100px_-40px_rgb(10_10_10/0.55),0_0_0_1px_rgb(255_255_255/0.06)_inset]",
1246
+ className
1247
+ ),
1248
+ style,
1249
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative aspect-[9/19.2] overflow-hidden rounded-[2.35rem] bg-background", children: [
1250
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "absolute left-1/2 top-2.5 z-10 h-[1.35rem] w-[5.6rem] -translate-x-1/2 rounded-full bg-[#0b0b0c]" }),
1251
+ children
1252
+ ] })
1253
+ }
1254
+ );
1255
+ }
1256
+ function BrowserFrame({
1257
+ url = "ochk.app",
1258
+ className,
1259
+ style,
1260
+ children
1261
+ }) {
1262
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1263
+ "div",
1264
+ {
1265
+ className: cn(
1266
+ "overflow-hidden rounded-[1.1rem] border border-border bg-card",
1267
+ "shadow-[0_40px_90px_-40px_rgb(10_10_10/0.45)]",
1268
+ className
1269
+ ),
1270
+ style,
1271
+ children: [
1272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-10 items-center gap-3 border-b border-border px-4", children: [
1273
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-hidden": true, className: "flex gap-1.5", children: [
1274
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2.5 rounded-full bg-[#ff5f57]" }),
1275
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2.5 rounded-full bg-[#febc2e]" }),
1276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2.5 rounded-full bg-[#28c840]" })
1277
+ ] }),
1278
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto flex h-6 min-w-0 max-w-[60%] flex-1 items-center justify-center rounded-md bg-muted px-3 text-[0.75rem] text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: url }) }),
1279
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "w-[2.6rem]" })
1280
+ ] }),
1281
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children })
1282
+ ]
1283
+ }
1284
+ );
1285
+ }
1286
+ function FloatChip({
1287
+ icon,
1288
+ title,
1289
+ detail,
1290
+ delay = 0,
1291
+ className,
1292
+ style
1293
+ }) {
1294
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1295
+ "div",
1296
+ {
1297
+ className: cn(
1298
+ "oca-animate-drift flex items-center gap-3 rounded-2xl border border-border bg-card/90 py-2.5 pl-2.5 pr-4 backdrop-blur-md",
1299
+ "shadow-[0_24px_50px_-24px_rgb(10_10_10/0.35)]",
1300
+ className
1301
+ ),
1302
+ style: { animationDelay: `${-delay}s`, ...style },
1303
+ children: [
1304
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-muted text-foreground [&_svg]:size-4", children: icon }) : null,
1305
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
1306
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] font-medium leading-tight", children: title }),
1307
+ detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-tight text-muted-foreground", children: detail }) : null
1308
+ ] })
1309
+ ]
1310
+ }
1311
+ );
1312
+ }
1121
1313
 
1122
1314
  exports.Accent = Accent;
1123
1315
  exports.ActivityList = ActivityList;
1316
+ exports.BrowserFrame = BrowserFrame;
1124
1317
  exports.CodeBlock = CodeBlock;
1125
1318
  exports.Container = Container;
1126
1319
  exports.CopyButton = CopyButton;
@@ -1131,6 +1324,7 @@ exports.DocLayout = DocLayout;
1131
1324
  exports.EmptyLine = EmptyLine;
1132
1325
  exports.EmptyState = EmptyState;
1133
1326
  exports.Eyebrow = Eyebrow;
1327
+ exports.FloatChip = FloatChip;
1134
1328
  exports.Footnote = Footnote;
1135
1329
  exports.HashChip = HashChip;
1136
1330
  exports.KeyValueList = KeyValueList;
@@ -1140,20 +1334,25 @@ exports.Notice = Notice;
1140
1334
  exports.PackageCard = PackageCard;
1141
1335
  exports.PageHeader = PageHeader;
1142
1336
  exports.PageHero = PageHero;
1337
+ exports.PhoneFrame = PhoneFrame;
1143
1338
  exports.ProgressSteps = ProgressSteps;
1144
1339
  exports.Prose = Prose;
1340
+ exports.Reveal = Reveal;
1145
1341
  exports.Sats = Sats;
1146
1342
  exports.SatsFigure = SatsFigure;
1343
+ exports.ScrollStory = ScrollStory;
1147
1344
  exports.Section = Section;
1148
1345
  exports.SectionIntro = SectionIntro;
1149
1346
  exports.SplitBar = SplitBar;
1150
1347
  exports.StatCard = StatCard;
1151
1348
  exports.StatGrid = StatGrid;
1152
1349
  exports.StepGrid = StepGrid;
1350
+ exports.Ticker = Ticker;
1153
1351
  exports.TruthTable = TruthTable;
1154
1352
  exports.UsdApprox = UsdApprox;
1155
1353
  exports.satsText = satsText;
1156
1354
  exports.sectionVariants = sectionVariants;
1157
1355
  exports.useCopy = useCopy;
1356
+ exports.useInView = useInView;
1158
1357
  //# sourceMappingURL=components.js.map
1159
1358
  //# sourceMappingURL=components.js.map