@orangecheck/app-design 0.4.0 → 0.4.2

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.mjs CHANGED
@@ -1229,6 +1229,131 @@ function Prose({ className, ...props }) {
1229
1229
  }
1230
1230
  );
1231
1231
  }
1232
+ function prefersStill() {
1233
+ return typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1234
+ }
1235
+ function useInView(rootMargin = "0px 0px -12% 0px") {
1236
+ const ref = useRef(null);
1237
+ const [seen, setSeen] = useState(false);
1238
+ useEffect(() => {
1239
+ const el = ref.current;
1240
+ if (!el || seen) return;
1241
+ if (typeof IntersectionObserver === "undefined") {
1242
+ setSeen(true);
1243
+ return;
1244
+ }
1245
+ const io = new IntersectionObserver(
1246
+ ([e]) => {
1247
+ if (e?.isIntersecting) {
1248
+ setSeen(true);
1249
+ io.disconnect();
1250
+ }
1251
+ },
1252
+ { rootMargin }
1253
+ );
1254
+ io.observe(el);
1255
+ return () => io.disconnect();
1256
+ }, [rootMargin, seen]);
1257
+ return [ref, seen];
1258
+ }
1259
+ function Reveal({
1260
+ as = "div",
1261
+ delay = 0,
1262
+ className,
1263
+ style,
1264
+ children
1265
+ }) {
1266
+ const ref = useRef(null);
1267
+ useEffect(() => {
1268
+ const el = ref.current;
1269
+ if (!el || prefersStill() || typeof IntersectionObserver === "undefined") return;
1270
+ if (el.getBoundingClientRect().top < window.innerHeight * 0.92) return;
1271
+ el.dataset.reveal = "pending";
1272
+ const io = new IntersectionObserver(
1273
+ ([e]) => {
1274
+ if (e?.isIntersecting) {
1275
+ el.dataset.reveal = "shown";
1276
+ io.disconnect();
1277
+ }
1278
+ },
1279
+ { rootMargin: "0px 0px -10% 0px" }
1280
+ );
1281
+ io.observe(el);
1282
+ return () => io.disconnect();
1283
+ }, []);
1284
+ return createElement(
1285
+ as,
1286
+ { ref, className, style: { ...style, "--reveal-delay": `${delay}ms` } },
1287
+ children
1288
+ );
1289
+ }
1290
+ function ScrollStory({
1291
+ length = 2,
1292
+ className,
1293
+ innerClassName,
1294
+ children
1295
+ }) {
1296
+ const ref = useRef(null);
1297
+ const [pinned, setPinned] = useState(false);
1298
+ useEffect(() => {
1299
+ const el = ref.current;
1300
+ if (!el || prefersStill()) return;
1301
+ setPinned(true);
1302
+ let raf = 0;
1303
+ const update = () => {
1304
+ raf = 0;
1305
+ const r = el.getBoundingClientRect();
1306
+ const travel = r.height - window.innerHeight;
1307
+ const p = travel > 0 ? Math.min(1, Math.max(0, -r.top / travel)) : 0;
1308
+ el.style.setProperty("--p", p.toFixed(4));
1309
+ };
1310
+ const on = () => {
1311
+ if (!raf) raf = requestAnimationFrame(update);
1312
+ };
1313
+ update();
1314
+ window.addEventListener("scroll", on, { passive: true });
1315
+ window.addEventListener("resize", on);
1316
+ return () => {
1317
+ cancelAnimationFrame(raf);
1318
+ window.removeEventListener("scroll", on);
1319
+ window.removeEventListener("resize", on);
1320
+ };
1321
+ }, []);
1322
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("relative", className), style: pinned ? { height: `${length * 100}svh` } : void 0, children: /* @__PURE__ */ jsx("div", { className: cn(pinned && "sticky top-0 flex min-h-svh items-center", innerClassName), children }) });
1323
+ }
1324
+ function Ticker({
1325
+ value,
1326
+ duration = 1200,
1327
+ format = (n) => Math.round(n).toLocaleString("en-US"),
1328
+ className
1329
+ }) {
1330
+ const [ref, seen] = useInView();
1331
+ const [shown, setShown] = useState(value);
1332
+ const animate = useRef(null);
1333
+ useEffect(() => {
1334
+ const el = ref.current;
1335
+ if (!el || animate.current !== null) return;
1336
+ animate.current = !prefersStill() && el.getBoundingClientRect().top > window.innerHeight * 0.9;
1337
+ if (animate.current) setShown(0);
1338
+ }, [ref]);
1339
+ useEffect(() => {
1340
+ if (!seen) return;
1341
+ if (!animate.current) {
1342
+ setShown(value);
1343
+ return;
1344
+ }
1345
+ let raf = 0;
1346
+ const t0 = performance.now();
1347
+ const step = (now) => {
1348
+ const k = Math.min(1, (now - t0) / duration);
1349
+ setShown(value * (1 - Math.pow(1 - k, 3)));
1350
+ if (k < 1) raf = requestAnimationFrame(step);
1351
+ };
1352
+ raf = requestAnimationFrame(step);
1353
+ return () => cancelAnimationFrame(raf);
1354
+ }, [seen, value, duration]);
1355
+ return /* @__PURE__ */ jsx("span", { ref, className: cn("oca-tabular", className), children: format(shown) });
1356
+ }
1232
1357
  var sectionVariants = cva("relative w-full overflow-x-clip", {
1233
1358
  variants: {
1234
1359
  tone: {
@@ -1257,19 +1382,12 @@ function Container({ className, ...props }) {
1257
1382
  function SectionIntro({
1258
1383
  className,
1259
1384
  align = "start",
1260
- ...props
1385
+ reveal = true,
1386
+ children,
1387
+ style
1261
1388
  }) {
1262
- return /* @__PURE__ */ jsx(
1263
- "div",
1264
- {
1265
- className: cn(
1266
- "flex flex-col gap-4 md:gap-5",
1267
- align === "center" && "mx-auto items-center text-center",
1268
- className
1269
- ),
1270
- ...props
1271
- }
1272
- );
1389
+ const cls = cn("flex flex-col gap-4 md:gap-5", align === "center" && "mx-auto items-center text-center", className);
1390
+ return reveal ? /* @__PURE__ */ jsx(Reveal, { className: cls, style, children }) : /* @__PURE__ */ jsx("div", { className: cls, style, children });
1273
1391
  }
1274
1392
  function PageHero({
1275
1393
  eyebrow,
@@ -1288,14 +1406,14 @@ function PageHero({
1288
1406
  }
1289
1407
  return /* @__PURE__ */ jsx(Section, { space: "none", className: cn("pb-14 pt-12 md:pb-20 md:pt-20", className), children: /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-10", art && "items-center md:grid-cols-12"), children: [
1290
1408
  /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-start gap-6", art ? "md:col-span-7" : "max-w-[52rem]"), children: [
1291
- eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1292
- /* @__PURE__ */ jsx("h1", { className: size === "xl" ? "oca-display-1" : "oca-display-2", children: title }),
1293
- lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead max-w-[38rem]", children: lead }) : null,
1294
- meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1295
- actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null,
1296
- children
1409
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow oca-enter", children: eyebrow }) : null,
1410
+ /* @__PURE__ */ jsx("h1", { className: cn(size === "xl" ? "oca-display-1" : "oca-display-2", "oca-enter [--enter-delay:70ms]"), children: title }),
1411
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead oca-enter max-w-[38rem] [--enter-delay:150ms]", children: lead }) : null,
1412
+ meta ? /* @__PURE__ */ jsx("p", { className: "oca-enter text-[0.875rem] text-muted-foreground [--enter-delay:190ms]", children: meta }) : null,
1413
+ actions ? /* @__PURE__ */ jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions }) : null,
1414
+ children ? /* @__PURE__ */ jsx("div", { className: "oca-enter w-full [--enter-delay:270ms]", children }) : null
1297
1415
  ] }),
1298
- art ? /* @__PURE__ */ jsx("div", { className: "md:col-span-5", children: art }) : null
1416
+ art ? /* @__PURE__ */ jsx("div", { className: "oca-enter md:col-span-5 [--enter-delay:120ms]", children: art }) : null
1299
1417
  ] }) });
1300
1418
  }
1301
1419
  function DocHeader({
@@ -1308,8 +1426,8 @@ function DocHeader({
1308
1426
  className
1309
1427
  }) {
1310
1428
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
1311
- eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1312
- /* @__PURE__ */ jsx("h1", { className: "oca-display-2", children: title }),
1429
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow oca-enter", children: eyebrow }) : null,
1430
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-2 oca-enter [--enter-delay:70ms]", children: title }),
1313
1431
  lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead", children: lead }) : null,
1314
1432
  meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1315
1433
  actions ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-3", children: actions }) : null,
@@ -1916,10 +2034,20 @@ function SplitBar({
1916
2034
  s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
1917
2035
  ),
1918
2036
  style: { flexBasis: `${s.pct}%` },
1919
- children: /* @__PURE__ */ jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
1920
- s.pct,
1921
- "%"
1922
- ] })
2037
+ children: /* @__PURE__ */ jsxs(
2038
+ "span",
2039
+ {
2040
+ className: cn(
2041
+ "oca-tabular leading-none tracking-[-0.02em]",
2042
+ // A small share gets a smaller figure, so it fits its segment at any width.
2043
+ s.pct < 30 ? "text-[1.125rem] md:text-[1.375rem]" : "text-[1.25rem] md:text-[1.875rem]"
2044
+ ),
2045
+ children: [
2046
+ s.pct,
2047
+ "%"
2048
+ ]
2049
+ }
2050
+ )
1923
2051
  },
1924
2052
  i
1925
2053
  )) }),
@@ -2057,131 +2185,6 @@ function SatsFigure({
2057
2185
  hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
2058
2186
  ] });
2059
2187
  }
2060
- function prefersStill() {
2061
- return typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2062
- }
2063
- function useInView(rootMargin = "0px 0px -12% 0px") {
2064
- const ref = useRef(null);
2065
- const [seen, setSeen] = useState(false);
2066
- useEffect(() => {
2067
- const el = ref.current;
2068
- if (!el || seen) return;
2069
- if (typeof IntersectionObserver === "undefined") {
2070
- setSeen(true);
2071
- return;
2072
- }
2073
- const io = new IntersectionObserver(
2074
- ([e]) => {
2075
- if (e?.isIntersecting) {
2076
- setSeen(true);
2077
- io.disconnect();
2078
- }
2079
- },
2080
- { rootMargin }
2081
- );
2082
- io.observe(el);
2083
- return () => io.disconnect();
2084
- }, [rootMargin, seen]);
2085
- return [ref, seen];
2086
- }
2087
- function Reveal({
2088
- as = "div",
2089
- delay = 0,
2090
- className,
2091
- style,
2092
- children
2093
- }) {
2094
- const ref = useRef(null);
2095
- useEffect(() => {
2096
- const el = ref.current;
2097
- if (!el || prefersStill() || typeof IntersectionObserver === "undefined") return;
2098
- if (el.getBoundingClientRect().top < window.innerHeight * 0.92) return;
2099
- el.dataset.reveal = "pending";
2100
- const io = new IntersectionObserver(
2101
- ([e]) => {
2102
- if (e?.isIntersecting) {
2103
- el.dataset.reveal = "shown";
2104
- io.disconnect();
2105
- }
2106
- },
2107
- { rootMargin: "0px 0px -10% 0px" }
2108
- );
2109
- io.observe(el);
2110
- return () => io.disconnect();
2111
- }, []);
2112
- return createElement(
2113
- as,
2114
- { ref, className, style: { ...style, "--reveal-delay": `${delay}ms` } },
2115
- children
2116
- );
2117
- }
2118
- function ScrollStory({
2119
- length = 2,
2120
- className,
2121
- innerClassName,
2122
- children
2123
- }) {
2124
- const ref = useRef(null);
2125
- const [pinned, setPinned] = useState(false);
2126
- useEffect(() => {
2127
- const el = ref.current;
2128
- if (!el || prefersStill()) return;
2129
- setPinned(true);
2130
- let raf = 0;
2131
- const update = () => {
2132
- raf = 0;
2133
- const r = el.getBoundingClientRect();
2134
- const travel = r.height - window.innerHeight;
2135
- const p = travel > 0 ? Math.min(1, Math.max(0, -r.top / travel)) : 0;
2136
- el.style.setProperty("--p", p.toFixed(4));
2137
- };
2138
- const on = () => {
2139
- if (!raf) raf = requestAnimationFrame(update);
2140
- };
2141
- update();
2142
- window.addEventListener("scroll", on, { passive: true });
2143
- window.addEventListener("resize", on);
2144
- return () => {
2145
- cancelAnimationFrame(raf);
2146
- window.removeEventListener("scroll", on);
2147
- window.removeEventListener("resize", on);
2148
- };
2149
- }, []);
2150
- return /* @__PURE__ */ jsx("div", { ref, className: cn("relative", className), style: pinned ? { height: `${length * 100}svh` } : void 0, children: /* @__PURE__ */ jsx("div", { className: cn(pinned && "sticky top-0 flex min-h-svh items-center", innerClassName), children }) });
2151
- }
2152
- function Ticker({
2153
- value,
2154
- duration = 1200,
2155
- format = (n) => Math.round(n).toLocaleString("en-US"),
2156
- className
2157
- }) {
2158
- const [ref, seen] = useInView();
2159
- const [shown, setShown] = useState(value);
2160
- const animate = useRef(null);
2161
- useEffect(() => {
2162
- const el = ref.current;
2163
- if (!el || animate.current !== null) return;
2164
- animate.current = !prefersStill() && el.getBoundingClientRect().top > window.innerHeight * 0.9;
2165
- if (animate.current) setShown(0);
2166
- }, [ref]);
2167
- useEffect(() => {
2168
- if (!seen) return;
2169
- if (!animate.current) {
2170
- setShown(value);
2171
- return;
2172
- }
2173
- let raf = 0;
2174
- const t0 = performance.now();
2175
- const step = (now) => {
2176
- const k = Math.min(1, (now - t0) / duration);
2177
- setShown(value * (1 - Math.pow(1 - k, 3)));
2178
- if (k < 1) raf = requestAnimationFrame(step);
2179
- };
2180
- raf = requestAnimationFrame(step);
2181
- return () => cancelAnimationFrame(raf);
2182
- }, [seen, value, duration]);
2183
- return /* @__PURE__ */ jsx("span", { ref, className: cn("oca-tabular", className), children: format(shown) });
2184
- }
2185
2188
  function PhoneFrame({ className, style, children }) {
2186
2189
  return /* @__PURE__ */ jsx(
2187
2190
  "div",