@orangecheck/design 0.8.0 → 0.9.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/dist/chrome.mjs CHANGED
@@ -1,11 +1,13 @@
1
1
  import { Boxes, ChevronDown, Check, CornerDownLeft, Plus, Loader2, Copy } from 'lucide-react';
2
2
  import Link5 from 'next/link';
3
+ import * as React from 'react';
3
4
  import { useState, useRef, useEffect, useId } from 'react';
4
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
6
  import { useRouter } from 'next/router';
6
- import { useOcSession, fetchOcLinkedIdentities } from '@orangecheck/auth-client';
7
+ import * as Popover from '@radix-ui/react-popover';
7
8
  import { clsx } from 'clsx';
8
9
  import { twMerge } from 'tailwind-merge';
10
+ import { useOcSession, fetchOcLinkedIdentities } from '@orangecheck/auth-client';
9
11
 
10
12
  // src/chrome/ecosystem-switcher.tsx
11
13
  var ENTRIES = [
@@ -186,6 +188,144 @@ function EcosystemSwitcher({
186
188
  )
187
189
  ] });
188
190
  }
191
+ function cn(...inputs) {
192
+ return twMerge(clsx(inputs));
193
+ }
194
+ var TOOLTIP_SURFACE_CLASS = "bg-popover text-popover-foreground border-border rounded-md border p-2.5 shadow-md";
195
+ var TOOLTIP_MOTION_CLASS = "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-1 data-[side=top]:slide-in-from-bottom-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 origin-(--radix-popover-content-transform-origin) duration-150 ease-out";
196
+ function compose(theirs, ours) {
197
+ return (e) => {
198
+ theirs?.(e);
199
+ ours(e);
200
+ };
201
+ }
202
+ var lastInputWasKeyboard = false;
203
+ var modalityInstalled = false;
204
+ function installModalityTracking() {
205
+ if (modalityInstalled || typeof window === "undefined") return;
206
+ modalityInstalled = true;
207
+ window.addEventListener("keydown", () => lastInputWasKeyboard = true, true);
208
+ window.addEventListener("pointerdown", () => lastInputWasKeyboard = false, true);
209
+ }
210
+ function Tooltip({
211
+ content,
212
+ children,
213
+ side = "bottom",
214
+ align = "start",
215
+ sideOffset = 8,
216
+ collisionPadding = 12,
217
+ openDelay = 300,
218
+ closeDelay = 90,
219
+ disabled = false,
220
+ portal = true,
221
+ zIndexClassName = "z-50",
222
+ contentClassName
223
+ }) {
224
+ const [hovering, setHovering] = React.useState(false);
225
+ const [focusing, setFocusing] = React.useState(false);
226
+ const [isFinePointer, setIsFinePointer] = React.useState(false);
227
+ const openTimer = React.useRef(null);
228
+ const closeTimer = React.useRef(null);
229
+ React.useEffect(() => {
230
+ installModalityTracking();
231
+ const mq = window.matchMedia("(hover: hover) and (pointer: fine)");
232
+ const apply = () => setIsFinePointer(mq.matches);
233
+ apply();
234
+ mq.addEventListener("change", apply);
235
+ return () => mq.removeEventListener("change", apply);
236
+ }, []);
237
+ const clearTimers = React.useCallback(() => {
238
+ if (openTimer.current) clearTimeout(openTimer.current);
239
+ if (closeTimer.current) clearTimeout(closeTimer.current);
240
+ }, []);
241
+ React.useEffect(() => clearTimers, [clearTimers]);
242
+ React.useEffect(() => {
243
+ if (disabled) {
244
+ clearTimers();
245
+ setHovering(false);
246
+ }
247
+ }, [disabled, clearTimers]);
248
+ const handlePointerEnter = () => {
249
+ if (!isFinePointer) return;
250
+ if (closeTimer.current) clearTimeout(closeTimer.current);
251
+ openTimer.current = setTimeout(() => setHovering(true), openDelay);
252
+ };
253
+ const handlePointerLeave = () => {
254
+ if (openTimer.current) clearTimeout(openTimer.current);
255
+ closeTimer.current = setTimeout(() => setHovering(false), closeDelay);
256
+ };
257
+ const handlePointerDown = () => {
258
+ clearTimers();
259
+ setHovering(false);
260
+ setFocusing(false);
261
+ };
262
+ const handleFocus = () => {
263
+ if (lastInputWasKeyboard) {
264
+ clearTimers();
265
+ setFocusing(true);
266
+ }
267
+ };
268
+ const handleBlur = () => {
269
+ clearTimers();
270
+ setFocusing(false);
271
+ };
272
+ const handleKeyDown = (e) => {
273
+ if (e.key === "Escape") {
274
+ clearTimers();
275
+ setHovering(false);
276
+ setFocusing(false);
277
+ }
278
+ };
279
+ const effectiveOpen = !disabled && (isFinePointer && hovering || focusing);
280
+ const extra = {};
281
+ const childProps = children.props;
282
+ extra.onPointerEnter = compose(childProps.onPointerEnter, handlePointerEnter);
283
+ extra.onPointerLeave = compose(childProps.onPointerLeave, handlePointerLeave);
284
+ extra.onPointerDown = compose(childProps.onPointerDown, handlePointerDown);
285
+ extra.onFocus = compose(childProps.onFocus, handleFocus);
286
+ extra.onBlur = compose(childProps.onBlur, handleBlur);
287
+ extra.onKeyDown = compose(childProps.onKeyDown, handleKeyDown);
288
+ const trigger = React.cloneElement(children, extra);
289
+ const contentEl = /* @__PURE__ */ jsx(
290
+ Popover.Content,
291
+ {
292
+ side,
293
+ align,
294
+ sideOffset,
295
+ collisionPadding,
296
+ "aria-hidden": true,
297
+ onOpenAutoFocus: (e) => e.preventDefault(),
298
+ onCloseAutoFocus: (e) => e.preventDefault(),
299
+ onFocusOutside: (e) => e.preventDefault(),
300
+ className: cn(
301
+ TOOLTIP_SURFACE_CLASS,
302
+ TOOLTIP_MOTION_CLASS,
303
+ "pointer-events-none",
304
+ zIndexClassName,
305
+ contentClassName
306
+ ),
307
+ children: content
308
+ }
309
+ );
310
+ return /* @__PURE__ */ jsxs(
311
+ Popover.Root,
312
+ {
313
+ open: effectiveOpen,
314
+ onOpenChange: (o) => {
315
+ if (!o) {
316
+ clearTimers();
317
+ setHovering(false);
318
+ setFocusing(false);
319
+ }
320
+ },
321
+ modal: false,
322
+ children: [
323
+ /* @__PURE__ */ jsx(Popover.Anchor, { asChild: true, children: trigger }),
324
+ portal ? /* @__PURE__ */ jsx(Popover.Portal, { children: contentEl }) : contentEl
325
+ ]
326
+ }
327
+ );
328
+ }
189
329
 
190
330
  // src/chrome/family-properties.ts
191
331
  var FAMILY_PROPERTIES = [
@@ -350,6 +490,31 @@ function MenuCategoryChip({ category }) {
350
490
  }
351
491
  );
352
492
  }
493
+ function SwitcherTooltipCard({ current }) {
494
+ const prop = findFamilyProperty(current);
495
+ return /* @__PURE__ */ jsxs("div", { className: "w-[13rem] max-w-[calc(100vw-1.5rem)]", children: [
496
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col leading-tight", children: [
497
+ /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-baseline gap-x-1.5", children: [
498
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[9px] tracking-widest uppercase", children: "you\u2019re on" }),
499
+ /* @__PURE__ */ jsx("span", { className: "text-primary font-display text-[12px] font-semibold tracking-tight", children: prop?.label ?? "orangecheck family" })
500
+ ] }),
501
+ prop?.sub && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground mt-0.5 font-mono text-[10px] tracking-wide", children: prop.sub })
502
+ ] }),
503
+ /* @__PURE__ */ jsx("div", { className: "border-border -mx-2.5 my-2 border-t" }),
504
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
505
+ /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "text-muted-foreground h-3 w-3 shrink-0" }),
506
+ /* @__PURE__ */ jsx("span", { className: "text-primary font-mono text-[10px] font-medium tracking-widest uppercase", children: "click" }),
507
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[10px]", children: "\xB7" }),
508
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[10px] tracking-wide", children: "switch site" })
509
+ ] }),
510
+ /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-1.5", children: [
511
+ /* @__PURE__ */ jsx(CornerDownLeft, { "aria-hidden": true, className: "text-muted-foreground h-3 w-3 shrink-0" }),
512
+ /* @__PURE__ */ jsx("span", { className: "text-primary font-mono text-[10px] font-medium tracking-widest uppercase", children: "double-click" }),
513
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[10px]", children: "\xB7" }),
514
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground font-mono text-[10px] tracking-wide", children: "home" })
515
+ ] })
516
+ ] });
517
+ }
353
518
  function OcLogoDropdown({
354
519
  current,
355
520
  homeHref = "/",
@@ -399,31 +564,45 @@ function OcLogoDropdown({
399
564
  "data-oc-current-category": currentCategory,
400
565
  "data-oc-site-state": siteState,
401
566
  children: [
402
- /* @__PURE__ */ jsxs(
403
- "button",
567
+ /* @__PURE__ */ jsx(
568
+ Tooltip,
404
569
  {
405
- type: "button",
406
- "aria-haspopup": "menu",
407
- "aria-expanded": open,
408
- "aria-controls": menuId,
409
- "aria-label": "OrangeCheck family \xB7 click to open property menu, double-click to go home",
410
- title: "single-click \xB7 family menu \xB7 double-click \xB7 go home",
411
- onClick: handleTriggerClick,
412
- className: triggerClassName ?? "group hover:bg-accent/30 -mx-1.5 -my-1 flex min-h-[40px] items-center gap-2 rounded-sm px-1.5 py-1 transition-colors " + (open ? "bg-accent/20" : ""),
413
- "data-oc-logo-dropdown-trigger": "",
414
- "data-oc-logo-dropdown-open": open ? "true" : "false",
415
- children: [
416
- children,
417
- /* @__PURE__ */ jsx(CategoryChip, { category: currentCategory }),
418
- /* @__PURE__ */ jsx(SiteStateBadge, { state: siteState }),
419
- /* @__PURE__ */ jsx(
420
- ChevronDown,
421
- {
422
- "aria-hidden": true,
423
- className: "text-muted-foreground/70 group-hover:text-foreground/80 h-3.5 w-3.5 shrink-0 transition-transform duration-200 " + (open ? "rotate-180" : "")
424
- }
425
- )
426
- ]
570
+ content: /* @__PURE__ */ jsx(SwitcherTooltipCard, { current }),
571
+ disabled: open,
572
+ side: "bottom",
573
+ align: "start",
574
+ sideOffset: 8,
575
+ zIndexClassName: "z-[70]",
576
+ children: /* @__PURE__ */ jsxs(
577
+ "button",
578
+ {
579
+ type: "button",
580
+ "aria-haspopup": "menu",
581
+ "aria-expanded": open,
582
+ "aria-controls": menuId,
583
+ "aria-label": "orangecheck family menu",
584
+ onClick: handleTriggerClick,
585
+ className: cn(
586
+ // focus indicator is guaranteed even if a consumer overrides triggerClassName
587
+ "focus-visible:ring-primary/60 rounded-sm focus-visible:ring-2 focus-visible:outline-none",
588
+ triggerClassName ?? "group hover:bg-accent/30 -mx-1.5 -my-1 flex min-h-[40px] items-center gap-2 rounded-sm px-1.5 py-1 transition-colors " + (open ? "bg-accent/20" : "")
589
+ ),
590
+ "data-oc-logo-dropdown-trigger": "",
591
+ "data-oc-logo-dropdown-open": open ? "true" : "false",
592
+ children: [
593
+ children,
594
+ /* @__PURE__ */ jsx(CategoryChip, { category: currentCategory }),
595
+ /* @__PURE__ */ jsx(SiteStateBadge, { state: siteState }),
596
+ /* @__PURE__ */ jsx(
597
+ ChevronDown,
598
+ {
599
+ "aria-hidden": true,
600
+ className: "text-muted-foreground/70 group-hover:text-foreground/80 h-3.5 w-3.5 shrink-0 transition-transform duration-200 " + (open ? "rotate-180" : "")
601
+ }
602
+ )
603
+ ]
604
+ }
605
+ )
427
606
  }
428
607
  ),
429
608
  /* @__PURE__ */ jsxs(
@@ -452,7 +631,7 @@ function OcLogoDropdown({
452
631
  {
453
632
  id: menuId,
454
633
  role: "menu",
455
- "aria-label": "OrangeCheck family",
634
+ "aria-label": "orangecheck family",
456
635
  className: popoverClassName ?? "bg-background absolute top-full left-0 z-[60] mt-2 w-[min(20rem,calc(100vw-1rem))] border shadow-lg",
457
636
  "data-oc-logo-dropdown-popover": "",
458
637
  children: [
@@ -1586,9 +1765,6 @@ function AppShell({
1586
1765
  /* @__PURE__ */ jsx("div", { className: hasHeader ? "mt-8 pb-12" : "pb-12", children })
1587
1766
  ] }) }) }) });
1588
1767
  }
1589
- function cn(...inputs) {
1590
- return twMerge(clsx(inputs));
1591
- }
1592
1768
  var HIDE = {
1593
1769
  sm: "hidden sm:inline",
1594
1770
  md: "hidden md:inline",