@xenide-io/the-old-ui-theme 0.2.9 → 0.3.0

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.
Files changed (61) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-SHF57J7U.mjs → chunk-FDMD3IIN.mjs} +1573 -652
  3. package/dist/index-D1RTT2Ap.d.mts +1044 -0
  4. package/dist/index-D1RTT2Ap.d.ts +1044 -0
  5. package/dist/index.d.mts +10 -7
  6. package/dist/index.d.ts +10 -7
  7. package/dist/index.js +1705 -744
  8. package/dist/index.mjs +61 -1
  9. package/dist/tailwind-preset.js +7 -0
  10. package/dist/tailwind-preset.mjs +7 -0
  11. package/dist/ui.d.mts +3 -2
  12. package/dist/ui.d.ts +3 -2
  13. package/dist/ui.js +1584 -666
  14. package/dist/ui.mjs +31 -1
  15. package/package.json +18 -4
  16. package/src/app/globals.css +1005 -227
  17. package/src/components/icons/IconBase.tsx +20 -12
  18. package/src/components/icons/createIconBase.tsx +12 -7
  19. package/src/components/icons/icons.tsx +208 -18
  20. package/src/components/sections/AlertShowcase.tsx +2 -1
  21. package/src/components/sections/BadgeShowcase.tsx +1 -1
  22. package/src/components/sections/ButtonShowcase.tsx +6 -10
  23. package/src/components/sections/CardShowcase.tsx +22 -6
  24. package/src/components/sections/DropdownShowcase.tsx +4 -6
  25. package/src/components/sections/FilterChipsShowcase.tsx +74 -26
  26. package/src/components/sections/FormShowcase.tsx +2 -1
  27. package/src/components/sections/IconShowcase.tsx +86 -206
  28. package/src/components/sections/KbdShowcase.tsx +47 -21
  29. package/src/components/sections/ModalShowcase.tsx +7 -6
  30. package/src/components/sections/ProductLayoutsShowcase.tsx +138 -0
  31. package/src/components/sections/ProgressShowcase.tsx +50 -53
  32. package/src/components/sections/SwapShowcase.tsx +13 -5
  33. package/src/components/ui/Alert.tsx +28 -19
  34. package/src/components/ui/AuthLayout.tsx +58 -0
  35. package/src/components/ui/Badge.tsx +10 -5
  36. package/src/components/ui/Button.tsx +22 -12
  37. package/src/components/ui/ButtonChrome.tsx +1 -1
  38. package/src/components/ui/Calendar.tsx +6 -7
  39. package/src/components/ui/Card.tsx +21 -11
  40. package/src/components/ui/CollapsibleSection.tsx +11 -11
  41. package/src/components/ui/DropdownMenu.tsx +189 -65
  42. package/src/components/ui/FilterBar.tsx +165 -0
  43. package/src/components/ui/FilterChips.tsx +65 -35
  44. package/src/components/ui/FilterControls.tsx +30 -0
  45. package/src/components/ui/FormField.tsx +69 -0
  46. package/src/components/ui/Input.tsx +166 -140
  47. package/src/components/ui/Kbd.tsx +88 -13
  48. package/src/components/ui/Loader.tsx +96 -0
  49. package/src/components/ui/Modal.tsx +66 -36
  50. package/src/components/ui/SettingsLayout.tsx +94 -0
  51. package/src/components/ui/ShowcaseWrapper.tsx +4 -16
  52. package/src/components/ui/Stepper.tsx +5 -6
  53. package/src/components/ui/first-slice.test.tsx +98 -0
  54. package/src/components/ui/index.ts +62 -3
  55. package/src/components/ui/interaction-primitives.test.tsx +77 -0
  56. package/src/components/ui/kbd-icons.test.tsx +90 -0
  57. package/src/components/ui/product-patterns.test.tsx +77 -0
  58. package/src/styles/themes.css +411 -1
  59. package/tailwind-preset.ts +7 -0
  60. package/dist/index-CmS6hcUk.d.mts +0 -753
  61. package/dist/index-CmS6hcUk.d.ts +0 -753
@@ -1,13 +1,13 @@
1
- import type { SVGAttributes } from "react";
1
+ import { forwardRef, type SVGAttributes } from "react";
2
2
  import { cn } from "@/lib/cn";
3
3
 
4
4
  export interface IconProps extends SVGAttributes<SVGSVGElement> {
5
- /** Pixel size or CSS length — defaults to `1em` (Lemon parity). */
5
+ /** Pixel size or CSS length; defaults to `1em`. */
6
6
  size?: number | string;
7
7
  }
8
8
 
9
- /** Base SVG wrapper — mirrors PostHog `LemonIconBase` + `.LemonIcon` metrics. */
10
- export function IconBase({
9
+ /** Shared SVG wrapper with predictable sizing and accessible-name behavior. */
10
+ export const IconBase = forwardRef<SVGSVGElement, IconProps>(function IconBase({
11
11
  className,
12
12
  size,
13
13
  children,
@@ -15,25 +15,33 @@ export function IconBase({
15
15
  fill = "none",
16
16
  xmlns = "http://www.w3.org/2000/svg",
17
17
  focusable = "false",
18
+ style,
19
+ role,
20
+ "aria-hidden": ariaHidden,
21
+ "aria-label": ariaLabel,
22
+ "aria-labelledby": ariaLabelledBy,
18
23
  ...props
19
- }: IconProps) {
20
- const dimensionProps =
21
- size != null
22
- ? { width: size, height: size }
23
- : {};
24
+ }, ref) {
25
+ const hasAccessibleName = Boolean(ariaLabel || ariaLabelledBy);
24
26
 
25
27
  return (
26
28
  <svg
29
+ ref={ref}
27
30
  className={cn("ph-icon", className)}
28
- {...dimensionProps}
29
31
  viewBox={viewBox}
30
32
  fill={fill}
31
33
  xmlns={xmlns}
32
34
  focusable={focusable}
33
- aria-hidden={props["aria-hidden"] ?? true}
35
+ role={role ?? (hasAccessibleName ? "img" : undefined)}
36
+ aria-hidden={ariaHidden ?? (hasAccessibleName ? undefined : true)}
37
+ aria-label={ariaLabel}
38
+ aria-labelledby={ariaLabelledBy}
39
+ style={{ width: size, height: size, ...style }}
34
40
  {...props}
35
41
  >
36
42
  {children}
37
43
  </svg>
38
44
  );
39
- }
45
+ });
46
+
47
+ IconBase.displayName = "IconBase";
@@ -1,26 +1,31 @@
1
- import type { ReactNode } from "react";
1
+ import { forwardRef, type ReactNode } from "react";
2
2
  import type { IconProps } from "@/components/icons/IconBase";
3
3
  import { IconBase } from "@/components/icons/IconBase";
4
4
 
5
5
  interface IconBaseDefinition {
6
+ name?: string;
6
7
  viewBox?: string;
7
8
  paths: ReactNode;
8
9
  }
9
10
 
10
- /** Factory for filled Lemon-style glyphs (Material / PostHog paths). */
11
- export function createIconBase({ viewBox = "0 0 24 24", paths }: IconBaseDefinition) {
12
- return function IconGlyph(props: IconProps) {
11
+ /** Factory for filled Old UI, Lemon, and Material-style glyphs. */
12
+ export function createIconBase({ name = "IconGlyph", viewBox = "0 0 24 24", paths }: IconBaseDefinition) {
13
+ const IconGlyph = forwardRef<SVGSVGElement, IconProps>(function IconGlyph(props, ref) {
13
14
  return (
14
- <IconBase viewBox={viewBox} {...props}>
15
+ <IconBase ref={ref} viewBox={viewBox} {...props}>
15
16
  {paths}
16
17
  </IconBase>
17
18
  );
18
- };
19
+ });
20
+
21
+ IconGlyph.displayName = name;
22
+ return IconGlyph;
19
23
  }
20
24
 
21
25
  /** Shorthand for single-path filled icons. */
22
- export function createIconBasePath(d: string, viewBox = "0 0 24 24") {
26
+ export function createIconBasePath(d: string, viewBox = "0 0 24 24", name?: string) {
23
27
  return createIconBase({
28
+ name,
24
29
  viewBox,
25
30
  paths: <path d={d} fill="currentColor" />,
26
31
  });
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Bespoke PostHog Lemon glyphs — paths sourced from PostHog open source
3
- * (`frontend/src/lib/lemon-ui/icons/icons.tsx`) and Material Design where noted.
2
+ * Filled product glyphs from PostHog/Material sources plus clearly labeled Old UI originals.
4
3
  */
4
+ import { forwardRef } from "react";
5
5
  import type { IconProps } from "@/components/icons/IconBase";
6
6
  import { createIconBase, createIconBasePath } from "@/components/icons/createIconBase";
7
7
  import { cn } from "@/lib/cn";
@@ -141,6 +141,13 @@ export const IconErrorOutline = createIconBase({
141
141
  ),
142
142
  });
143
143
 
144
+ export const IconInfo = createIconBase({
145
+ name: "IconInfo",
146
+ paths: fill(
147
+ "M11 10h2v7h-2v-7zm0-3h2v2h-2V7zm1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z",
148
+ ),
149
+ });
150
+
144
151
  export const IconCancel = createIconBase({
145
152
  paths: fill(
146
153
  "m12 2c-5.53 0-10 4.47-10 10s4.47 10 10 10 10-4.47 10-10-4.47-10-10-10zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13-3.59 3.59-3.59-3.59-1.41 1.41 3.59 3.59-3.59 3.59 1.41 1.41 3.59-3.59 3.59 3.59 1.41-1.41-3.59-3.59 3.59-3.59z",
@@ -272,7 +279,152 @@ export const IconRocket = createIconBasePath(
272
279
  "M9.19 6.35c-2.04 2.29-3.44 5.58-3.57 5.89L2 10.69l4.05-4.05c.47-.47 1.15-.68 1.81-.55l1.33 1.26zm5.45 8.67l-1.33-1.26c-.66-.13-1.34.08-1.81.55L2 18.31l3.62 3.57c.31-.13 3.6-1.53 5.89-3.57 1.53-1.72 2.52-3.76 2.87-5.02zM12 2c-1.1 0-2 .9-2 2v1.09c2.84.48 5 2.94 5 5.91 0 2.97-2.16 5.43-5 5.91V20c0 1.1.9 2 2 2s2-.9 2-2v-1.09c-2.84-.48-5-2.94-5-5.91 0-2.97 2.16-5.43 5-5.91V4c0-1.1-.9-2-2-2z",
273
280
  );
274
281
 
275
- export const IconTerminal = createIconBasePath("M20 4H4c-1.11 0-2 .89-2 2v12c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4V8l8 5 8-5v10zm-8-7L4 6h16l-8 5z");
282
+ export const IconTerminal = createIconBase({
283
+ name: "IconTerminal",
284
+ paths: (
285
+ <path
286
+ d="M3 4v16h18V4H3zm2 2h14v12H5V6zm2 2.2L10.8 12 7 15.8 8.4 17.2l5.2-5.2-5.2-5.2L7 8.2zM13 17h5v-2h-5v2z"
287
+ fill="currentColor"
288
+ fillRule="evenodd"
289
+ clipRule="evenodd"
290
+ />
291
+ ),
292
+ });
293
+
294
+ // —— Old UI originals: authored for this library's tactile product language ——
295
+ export const IconOldWindow = createIconBase({
296
+ name: "IconOldWindow",
297
+ paths: (
298
+ <path
299
+ d="M3 3v18h18V3H3zm2 7v9h14v-9H5zm1-4h2v1H6V6zm3 0h2v1H9V6z"
300
+ fill="currentColor"
301
+ fillRule="evenodd"
302
+ clipRule="evenodd"
303
+ />
304
+ ),
305
+ });
306
+
307
+ export const IconCommandCursor = createIconBase({
308
+ name: "IconCommandCursor",
309
+ paths: (
310
+ <path
311
+ d="M4 3v18h16V3H4zm2 2h12v14H6V5zm1.5 3.5L11 12l-3.5 3.5L9 17l5-5-5-5-1.5 1.5zM13 17h4v-2h-4v2z"
312
+ fill="currentColor"
313
+ fillRule="evenodd"
314
+ clipRule="evenodd"
315
+ />
316
+ ),
317
+ });
318
+
319
+ export const IconDataReel = createIconBase({
320
+ name: "IconDataReel",
321
+ paths: (
322
+ <path
323
+ d="M3 5v14h18V5H3zm2 2h14v10H5V7zm3 1a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm8 0a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM10 11h4v1.5h-4V11z"
324
+ fill="currentColor"
325
+ fillRule="evenodd"
326
+ clipRule="evenodd"
327
+ />
328
+ ),
329
+ });
330
+
331
+ export const IconCodePreview = createIconBase({
332
+ name: "IconCodePreview",
333
+ paths: (
334
+ <path
335
+ d="M3 3v15h18V3H3zm2 2h14v11H5V5zm3.5 2L5 10.5 8.5 14l1.4-1.4-2.1-2.1 2.1-2.1L8.5 7zm7 0-1.4 1.4 2.1 2.1-2.1 2.1 1.4 1.4 3.5-3.5L15.5 7zM9 20h6v2H9v-2z"
336
+ fill="currentColor"
337
+ fillRule="evenodd"
338
+ clipRule="evenodd"
339
+ />
340
+ ),
341
+ });
342
+
343
+ export const IconInsightBoard = createIconBase({
344
+ name: "IconInsightBoard",
345
+ paths: (
346
+ <path
347
+ d="M3 3v18h18V3H3zm2 2h14v3H5V5zm0 5h6v9H5v-9zm8 0h6v4h-6v-4zm0 6h6v3h-6v-3zM6 6h2v1H6V6zm3 0h2v1H9V6z"
348
+ fill="currentColor"
349
+ fillRule="evenodd"
350
+ clipRule="evenodd"
351
+ />
352
+ ),
353
+ });
354
+
355
+ export const IconEventStream = createIconBase({
356
+ name: "IconEventStream",
357
+ paths: (
358
+ <>
359
+ <path d="M5 4h2v16H5V4z" fill="currentColor" opacity="0.45" />
360
+ {fill("M6 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm0 8a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm5-6h10v2H11V5zm0 8h7v2h-7v-2zm0 5h10v2H11v-2z")}
361
+ </>
362
+ ),
363
+ });
364
+
365
+ export const IconFeatureGate = createIconBase({
366
+ name: "IconFeatureGate",
367
+ paths: (
368
+ <path
369
+ d="M4 3h2v18H4V3zm3 2h12l-3 4 3 4H7V5zm4 1-2.2 4H12l-1 4 4.2-5H12l1-3h-2z"
370
+ fill="currentColor"
371
+ fillRule="evenodd"
372
+ clipRule="evenodd"
373
+ />
374
+ ),
375
+ });
376
+
377
+ export const IconReplayFrame = createIconBase({
378
+ name: "IconReplayFrame",
379
+ paths: (
380
+ <path
381
+ d="M3 3v18h18V3H3zm2 2h14v11H5V5zm5 2v7l6-3.5L10 7zm-5 11h9v1H5v-1zm11 0h3v1h-3v-1z"
382
+ fill="currentColor"
383
+ fillRule="evenodd"
384
+ clipRule="evenodd"
385
+ />
386
+ ),
387
+ });
388
+
389
+ export const IconQueryStack = createIconBase({
390
+ name: "IconQueryStack",
391
+ paths: fill(
392
+ "M4 5c0-1.66 3.58-3 8-3s8 1.34 8 3-3.58 3-8 3-8-1.34-8-3zm0 3v3c0 1.66 3.58 3 8 3 .7 0 1.38-.04 2-.12V11.8c-.64.13-1.31.2-2 .2-4.42 0-8-1.34-8-3zm0 6v3c0 1.66 3.58 3 8 3 .7 0 1.38-.04 2-.12v-2.08c-.64.13-1.31.2-2 .2-4.42 0-8-1.34-8-3zm12-1 5 4-5 4v-3h-4v-2h4v-3z",
393
+ ),
394
+ });
395
+
396
+ export const IconExperimentSplit = createIconBase({
397
+ name: "IconExperimentSplit",
398
+ paths: fill(
399
+ "M5 3a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm14 0a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM5 15a3 3 0 1 0 0 6 3 3 0 0 0 0-6zm1-6h2c0 2.2 1.8 4 4 4h2.17A3 3 0 0 1 19 11v2a3 3 0 0 1-4.83-2H12a6 6 0 0 1-6-6v4zm0 4a6 6 0 0 0 6-6h2a8 8 0 0 1-8 8v-2z",
400
+ ),
401
+ });
402
+
403
+ export const IconSurveyCard = createIconBase({
404
+ name: "IconSurveyCard",
405
+ paths: (
406
+ <path
407
+ d="M3 3v18h18V3H3zm2 2h14v14H5V5zm2 2h7v2H7V7zm0 4h4v2H7v-2zm7-.4-2.5 2.5-1-1-1.4 1.4 2.4 2.4 3.9-3.9-1.4-1.4zM7 16h10v1H7v-1z"
408
+ fill="currentColor"
409
+ fillRule="evenodd"
410
+ clipRule="evenodd"
411
+ />
412
+ ),
413
+ });
414
+
415
+ export const OLD_UI_ICONS = {
416
+ oldWindow: IconOldWindow,
417
+ commandCursor: IconCommandCursor,
418
+ dataReel: IconDataReel,
419
+ codePreview: IconCodePreview,
420
+ insightBoard: IconInsightBoard,
421
+ eventStream: IconEventStream,
422
+ featureGate: IconFeatureGate,
423
+ replayFrame: IconReplayFrame,
424
+ queryStack: IconQueryStack,
425
+ experimentSplit: IconExperimentSplit,
426
+ surveyCard: IconSurveyCard,
427
+ } as const;
276
428
 
277
429
  export const IconActivity = createIconBasePath(
278
430
  "M22 12h-4l-3 9L9 3l-3 9H2v2h6.76l2.24-6.72L15 15l2.24-6.72L19 14h3v-2z",
@@ -283,12 +435,14 @@ export const IconFlask = createIconBasePath(
283
435
  );
284
436
 
285
437
  /** Busy-state spinner — PostHog `IconSync` with spin animation. */
286
- export function IconSpinner({ className, ...props }: IconProps) {
287
- return <IconSync className={cn("ph-icon-spin", className)} {...props} />;
288
- }
438
+ export const IconSpinner = forwardRef<SVGSVGElement, IconProps>(function IconSpinner({ className, ...props }, ref) {
439
+ return <IconSync ref={ref} className={cn("ph-icon-spin", className)} {...props} />;
440
+ });
289
441
 
290
- /** Alias map for showcase / migration from Lucide names. */
291
- export const PH_ICONS = {
442
+ IconSpinner.displayName = "IconSpinner";
443
+
444
+ /** Canonical names power documentation and new dynamic-icon usage. */
445
+ export const CANONICAL_ICONS = {
292
446
  activity: IconActivity,
293
447
  areaChart: IconAreaChart,
294
448
  arrowDown: IconArrowDown,
@@ -303,65 +457,101 @@ export const PH_ICONS = {
303
457
  chevronDown: IconChevronDown,
304
458
  chevronLeft: IconChevronLeft,
305
459
  chevronRight: IconChevronRight,
306
- clipboard: IconClipboardEdit,
460
+ clipboardEdit: IconClipboardEdit,
307
461
  close: IconClose,
462
+ codePreview: IconCodePreview,
308
463
  cohort: IconCohort,
464
+ commandCursor: IconCommandCursor,
309
465
  copy: IconCopy,
310
466
  cumulativeChart: IconCumulativeChart,
467
+ dataReel: IconDataReel,
311
468
  database: IconDatabase,
312
469
  download: IconDownload,
313
470
  edit: IconEdit,
314
471
  errorOutline: IconErrorOutline,
472
+ eventStream: IconEventStream,
315
473
  exclamation: IconExclamation,
474
+ experimentSplit: IconExperimentSplit,
475
+ featureGate: IconFeatureGate,
316
476
  flag: IconFlag,
317
477
  flare: IconFlare,
318
478
  flask: IconFlask,
319
479
  gift: IconGift,
320
- grid: IconGridView,
480
+ gridView: IconGridView,
321
481
  handClick: IconHandClick,
322
482
  home: IconHome,
323
- info: IconErrorOutline,
483
+ info: IconInfo,
484
+ insightBoard: IconInsightBoard,
324
485
  layers: IconLayers,
325
- list: IconListView,
486
+ listView: IconListView,
326
487
  logout: IconLogout,
327
488
  mail: IconMail,
328
489
  moon: IconMoon,
490
+ oldWindow: IconOldWindow,
329
491
  panelRight: IconPanelRight,
330
492
  person: IconPerson,
331
- play: IconPlayCircle,
493
+ playCircle: IconPlayCircle,
332
494
  plus: IconPlus,
333
495
  premium: IconPremium,
334
496
  queryEditor: IconQueryEditor,
497
+ queryStack: IconQueryStack,
335
498
  radar: IconRadar,
336
499
  recording: IconRecording,
500
+ replayFrame: IconReplayFrame,
337
501
  robot: IconRobot,
338
502
  rocket: IconRocket,
339
503
  save: IconSave,
340
504
  search: IconSearch,
341
505
  selectEvents: IconSelectEvents,
342
- settings: IconTuning,
343
506
  shoppingCart: IconShoppingCart,
344
507
  spinner: IconSpinner,
345
508
  star: IconStar,
346
509
  subArrowRight: IconSubArrowRight,
347
510
  sun: IconSun,
511
+ surveyCard: IconSurveyCard,
348
512
  surveys: IconSurveys,
349
513
  sync: IconSync,
350
514
  tableChart: IconTableChart,
351
515
  terminal: IconTerminal,
352
516
  toggle: IconToggle,
353
517
  trash: IconTrash,
354
- trendingUp: IconArrowUp,
518
+ tuning: IconTuning,
355
519
  upload: IconUpload,
356
520
  volume: IconVolume,
357
521
  volumeOff: IconVolumeOff,
522
+ } as const;
523
+
524
+ /** Compatibility names remain runtime-identical to their canonical glyphs. */
525
+ export const PH_ICON_ALIASES = {
526
+ clipboard: IconClipboardEdit,
527
+ grid: IconGridView,
528
+ list: IconListView,
529
+ play: IconPlayCircle,
530
+ settings: IconTuning,
531
+ trendingUp: IconArrowUp,
358
532
  warning: IconExclamation,
359
533
  xCircle: IconCancel,
360
534
  } as const;
361
535
 
536
+ export const PH_ICONS = {
537
+ ...CANONICAL_ICONS,
538
+ ...PH_ICON_ALIASES,
539
+ } as const;
540
+
541
+ for (const [name, Icon] of Object.entries(CANONICAL_ICONS)) {
542
+ const namedIcon = Icon as typeof Icon & { displayName?: string };
543
+ if (!namedIcon.displayName || namedIcon.displayName === "IconGlyph") {
544
+ namedIcon.displayName = `Icon${name[0].toUpperCase()}${name.slice(1)}`;
545
+ }
546
+ }
547
+
548
+ export type CanonicalIconName = keyof typeof CANONICAL_ICONS;
549
+ export type IconAliasName = keyof typeof PH_ICON_ALIASES;
362
550
  export type IconName = keyof typeof PH_ICONS;
363
551
 
364
- export function IconByName({ name, ...props }: IconProps & { name: IconName }) {
552
+ export const IconByName = forwardRef<SVGSVGElement, IconProps & { name: IconName }>(function IconByName({ name, ...props }, ref) {
365
553
  const Icon = PH_ICONS[name];
366
- return <Icon {...props} />;
367
- }
554
+ return <Icon ref={ref} {...props} />;
555
+ });
556
+
557
+ IconByName.displayName = "IconByName";
@@ -1,7 +1,7 @@
1
1
  import { Alert, ComponentDocs, ShowcaseWrapper } from "@/components/ui";
2
2
 
3
3
  export default function AlertShowcase() {
4
- const code = `import { Alert } from "the-old-ui";
4
+ const code = `import { Alert } from "@xenide-io/the-old-ui-theme";
5
5
 
6
6
  <div className="space-y-4">
7
7
  <Alert status="info" title="Pipeline delay" description="Events are flowing; warehouse sync may lag by ~2 minutes." />
@@ -24,6 +24,7 @@ export default function AlertShowcase() {
24
24
  { name: "description", type: "string", description: "Supporting message copy." },
25
25
  { name: "onDismiss", type: "() => void", description: "Shows a close button when provided." },
26
26
  { name: "icon", type: "ReactNode", description: "Optional custom icon override." },
27
+ { name: "live", type: "off | polite | assertive", description: "Opt into live-region announcements for content that appears dynamically." },
27
28
  ]}
28
29
  />
29
30
  }
@@ -1,7 +1,7 @@
1
1
  import { Badge, ComponentDocs, ShowcaseWrapper } from "@/components/ui";
2
2
 
3
3
  export default function BadgeShowcase() {
4
- const code = `import { Badge } from "the-old-ui";
4
+ const code = `import { Badge } from "@xenide-io/the-old-ui-theme";
5
5
 
6
6
  <div className="ph-panel space-y-6">
7
7
  <div>
@@ -3,7 +3,6 @@ import {
3
3
  IconPlayCircle,
4
4
  IconPlus,
5
5
  IconSave,
6
- IconSpinner,
7
6
  IconSubArrowRight,
8
7
  IconTrash,
9
8
  IconUpload,
@@ -11,8 +10,7 @@ import {
11
10
  import { Button, ComponentDocs, DropdownButton, DropdownItem, Panel, ShowcaseWrapper } from "@/components/ui";
12
11
 
13
12
  export default function ButtonShowcase() {
14
- const code = `import { IconDownload, IconPlayCircle, IconPlus, IconSave, IconSpinner, IconSubArrowRight, IconTrash, IconUpload } from "the-old-ui";
15
- import { Button, DropdownButton, DropdownItem, Panel } from "the-old-ui";
13
+ const code = `import { Button, DropdownButton, DropdownItem, IconDownload, IconPlayCircle, IconPlus, IconSave, IconSubArrowRight, IconTrash, IconUpload, Panel } from "@xenide-io/the-old-ui-theme";
16
14
 
17
15
  <div className="space-y-8">
18
16
  <Panel className="space-y-4">
@@ -144,9 +142,7 @@ import { Button, DropdownButton, DropdownItem, Panel } from "the-old-ui";
144
142
  <Button variant="primary" disabled>
145
143
  Disabled
146
144
  </Button>
147
- <Button variant="primary" icon={<IconSpinner className="h-4 w-4" aria-hidden />}>
148
- Loading
149
- </Button>
145
+ <Button variant="primary" loading>Loading</Button>
150
146
  </div>
151
147
  </Panel>
152
148
  </div>`;
@@ -154,7 +150,7 @@ import { Button, DropdownButton, DropdownItem, Panel } from "the-old-ui";
154
150
  return (
155
151
  <ShowcaseWrapper
156
152
  title="Buttons"
157
- description="Reusable primitives from the-old-ui — Button, DropdownButton, SearchInput. Primary/secondary Lemon chrome from PostHog LemonButton.scss."
153
+ description="Every filled variant shares the same bordered face, lower frame, hover lift, and pressed depth. Ghost and link actions stay flat."
158
154
  code={code}
159
155
  filename="ButtonExample.tsx"
160
156
  docs={
@@ -167,6 +163,8 @@ import { Button, DropdownButton, DropdownItem, Panel } from "the-old-ui";
167
163
  { name: "icon", type: "ReactNode", description: "Leading icon slot." },
168
164
  { name: "sideIcon", type: "ReactNode", description: "Trailing icon slot." },
169
165
  { name: "split", type: "boolean", defaultValue: "false", description: "Adds split divider before the trailing slot." },
166
+ { name: "loading", type: "boolean", defaultValue: "false", description: "Disables the action, exposes aria-busy, and replaces the leading icon with a spinner." },
167
+ { name: "loadingLabel", type: "ReactNode", description: "Optional label shown while loading; the normal label stays in place by default." },
170
168
  ]}
171
169
  />
172
170
  }
@@ -301,9 +299,7 @@ import { Button, DropdownButton, DropdownItem, Panel } from "the-old-ui";
301
299
  <Button variant="primary" disabled>
302
300
  Disabled
303
301
  </Button>
304
- <Button variant="primary" icon={<IconSpinner className="h-4 w-4" aria-hidden />}>
305
- Loading
306
- </Button>
302
+ <Button variant="primary" loading>Loading</Button>
307
303
  </div>
308
304
  </Panel>
309
305
  </div>
@@ -1,12 +1,12 @@
1
1
  import { Badge, Button, Card, ComponentDocs, ShowcaseWrapper } from "@/components/ui";
2
2
 
3
3
  export default function CardShowcase() {
4
- const code = `import { Badge, Button, Card } from "the-old-ui";
4
+ const code = `import { Badge, Button, Card } from "@xenide-io/the-old-ui-theme";
5
5
 
6
6
  <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
7
7
  <Card
8
8
  title="Insight saved"
9
- description="White surface, hairline border, orange hover ring — mimics dashboard tiles."
9
+ description="A quiet, static surface. Depth is reserved for interactive or elevated content."
10
10
  actions={
11
11
  <>
12
12
  <Button variant="secondary" outline>
@@ -19,7 +19,7 @@ export default function CardShowcase() {
19
19
 
20
20
  <Card
21
21
  title="With visual"
22
- description="Same card shell — media sits flush to the border like product cards."
22
+ description="Media sits flush to the card edge with a semantic divider."
23
23
  media={<div className="flex h-40 items-center justify-center bg-gradient-to-br from-orange-400 via-ph-brand to-ph-blue text-lg font-bold text-white">Hero stripe</div>}
24
24
  actions={
25
25
  <Button variant="primary" size="sm">
@@ -60,12 +60,19 @@ export default function CardShowcase() {
60
60
  description="Grey trays on canvas — mirrors secondary surfaces in-app."
61
61
  actions={<Button variant="primary" outline>Inspect</Button>}
62
62
  />
63
+
64
+ <Card
65
+ interactive
66
+ title="Interactive surface"
67
+ description="Hover depth is opt-in for cards containing an action."
68
+ actions={<Button variant="tertiary">Review</Button>}
69
+ />
63
70
  </div>`;
64
71
 
65
72
  return (
66
73
  <ShowcaseWrapper
67
74
  title="Cards"
68
- description="Reusable card shell with title, description, actions, media, footer, and variant props."
75
+ description="Static by default, with explicit elevated, highlighted, and interactive treatments."
69
76
  code={code}
70
77
  filename="CardExample.tsx"
71
78
  docs={
@@ -76,6 +83,8 @@ export default function CardShowcase() {
76
83
  { name: "description", type: "ReactNode", description: "Optional supporting copy." },
77
84
  { name: "actions", type: "ReactNode", description: "Button row rendered with card action spacing." },
78
85
  { name: "media", type: "ReactNode", description: "Optional visual block rendered above the card body." },
86
+ { name: "interactive", type: "boolean", defaultValue: "false", description: "Adds hover and focus-within depth for a card containing an action." },
87
+ { name: "titleAs", type: "h2 | h3 | h4", defaultValue: "h3", description: "Selects the semantic heading level without changing the card style." },
79
88
  ]}
80
89
  />
81
90
  }
@@ -83,7 +92,7 @@ export default function CardShowcase() {
83
92
  <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
84
93
  <Card
85
94
  title="Insight saved"
86
- description="White surface, hairline border, orange hover ring — mimics dashboard tiles."
95
+ description="A quiet, static surface. Depth is reserved for interactive or elevated content."
87
96
  actions={
88
97
  <>
89
98
  <Button variant="secondary" outline>
@@ -96,7 +105,7 @@ export default function CardShowcase() {
96
105
 
97
106
  <Card
98
107
  title="With visual"
99
- description="Same card shell — media sits flush to the border like product cards."
108
+ description="Media sits flush to the card edge with a semantic divider."
100
109
  media={<div className="flex h-40 items-center justify-center bg-gradient-to-br from-orange-400 via-ph-brand to-ph-blue text-lg font-bold text-white">Hero stripe</div>}
101
110
  actions={
102
111
  <Button variant="primary" size="sm">
@@ -137,6 +146,13 @@ export default function CardShowcase() {
137
146
  description="Grey trays on canvas — mirrors secondary surfaces in-app."
138
147
  actions={<Button variant="primary" outline>Inspect</Button>}
139
148
  />
149
+
150
+ <Card
151
+ interactive
152
+ title="Interactive surface"
153
+ description="Hover depth is opt-in for cards containing an action."
154
+ actions={<Button variant="tertiary">Review</Button>}
155
+ />
140
156
  </div>
141
157
  </ShowcaseWrapper>
142
158
  );
@@ -4,8 +4,8 @@ import { IconCopy, IconEdit, IconLogout, IconPerson, IconTrash, IconTuning } fro
4
4
  import { DropdownButton, DropdownItem, ShowcaseWrapper } from "@/components/ui";
5
5
 
6
6
  export default function DropdownShowcase() {
7
- const code = `import { IconCopy, IconEdit, IconLogout, IconPerson, IconTrash, IconTuning } from "the-old-ui";
8
- import { DropdownButton, DropdownItem } from "the-old-ui";
7
+ const code = `import { IconCopy, IconEdit, IconLogout, IconPerson, IconTrash, IconTuning } from "@xenide-io/the-old-ui-theme";
8
+ import { DropdownButton, DropdownItem } from "@xenide-io/the-old-ui-theme";
9
9
 
10
10
  <div className="ph-panel space-y-6">
11
11
  <p className="text-sm text-ph-subtle">
@@ -51,15 +51,13 @@ import { DropdownButton, DropdownItem } from "the-old-ui";
51
51
  return (
52
52
  <ShowcaseWrapper
53
53
  title="Dropdowns"
54
- description="Use DropdownButton from the-old-ui — labelled Lemon triggers + DropdownItem menu rows."
54
+ description="Accessible menu buttons with keyboard navigation and automatic viewport-aware side flipping and alignment shifting."
55
55
  code={code}
56
56
  filename="DropdownExample.tsx"
57
57
  >
58
58
  <div className="ph-panel space-y-6">
59
59
  <p className="text-sm text-ph-subtle">
60
- Use <code className="ph-kbd">DropdownButton</code> from{" "}
61
- <code className="ph-kbd">the-old-ui</code> — labelled Lemon triggers +{" "}
62
- <code className="ph-kbd">DropdownItem</code> menu rows.
60
+ Menus prefer the requested side, then flip above or sideways and shift start/end alignment to remain visible.
63
61
  </p>
64
62
 
65
63
  <div className="flex flex-wrap items-start gap-6">