@exegia/corpora-ui 0.22.0 → 0.24.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 (42) hide show
  1. package/dist-lib/components/blocks/auth/__tests__/auth-flow-block.test.d.ts +1 -0
  2. package/dist-lib/components/blocks/auth/auth-flow-block.d.ts +123 -0
  3. package/dist-lib/components/blocks/scaffold/__tests__/scaffold-atom.test.d.ts +1 -0
  4. package/dist-lib/components/blocks/scaffold/index.d.ts +2 -0
  5. package/dist-lib/components/blocks/scaffold/scaffold-atom.d.ts +97 -0
  6. package/dist-lib/components/blocks/scaffold/scaffold-context.d.ts +3 -1
  7. package/dist-lib/components/blocks/scaffold/scaffold-root.d.ts +12 -3
  8. package/dist-lib/components/blocks/scaffold/type.d.ts +58 -18
  9. package/dist-lib/components/blocks/scaffold/use-scaffold-state.d.ts +26 -0
  10. package/dist-lib/components/blocks/scaffold/use-scaffold.d.ts +7 -1
  11. package/dist-lib/components/blocks/scaffold/utils.d.ts +11 -1
  12. package/dist-lib/components/ui/switch.d.ts +4 -0
  13. package/dist-lib/index.d.ts +1 -0
  14. package/dist-lib/index.js +1683 -1495
  15. package/dist-lib/index.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/components/beste/piece/browser-frame.tsx +1 -1
  18. package/src/components/beste/piece/utils.ts +4 -4
  19. package/src/components/blocks/auth/__tests__/auth-flow-block.test.tsx +183 -0
  20. package/src/components/blocks/auth/auth-flow-block.tsx +296 -0
  21. package/src/components/blocks/scaffold/__tests__/scaffold-atom.test.tsx +210 -0
  22. package/src/components/blocks/scaffold/index.ts +15 -0
  23. package/src/components/blocks/scaffold/scaffold-actions.tsx +5 -1
  24. package/src/components/blocks/scaffold/scaffold-atom.ts +383 -0
  25. package/src/components/blocks/scaffold/scaffold-canvas.tsx +12 -4
  26. package/src/components/blocks/scaffold/scaffold-context.ts +3 -1
  27. package/src/components/blocks/scaffold/scaffold-inspector.tsx +9 -2
  28. package/src/components/blocks/scaffold/scaffold-panel.tsx +24 -10
  29. package/src/components/blocks/scaffold/scaffold-root.tsx +64 -32
  30. package/src/components/blocks/scaffold/scaffold-sub-panel.tsx +12 -10
  31. package/src/components/blocks/scaffold/scaffold-tab.tsx +13 -9
  32. package/src/components/blocks/scaffold/type.ts +64 -18
  33. package/src/components/blocks/scaffold/use-scaffold-state.ts +58 -0
  34. package/src/components/blocks/scaffold/use-scaffold.ts +30 -19
  35. package/src/components/blocks/scaffold/utils.ts +45 -1
  36. package/src/components/blocks/shell/shell-layout.tsx +8 -3
  37. package/src/components/docs/component-preview.tsx +7 -2
  38. package/src/components/docs/demo-controls.tsx +32 -23
  39. package/src/components/ui/switch.tsx +30 -0
  40. package/src/index.ts +1 -0
  41. package/dist-lib/components/blocks/scaffold/use-panel-visibility.d.ts +0 -19
  42. package/src/components/blocks/scaffold/use-panel-visibility.ts +0 -180
@@ -40,7 +40,12 @@ export function ShellLayout({
40
40
  <AnimatedPanelProvider
41
41
  {...panelControlProps}
42
42
  defaultOpen={initialOpen}
43
- className={cn("relative h-full min-h-0 px-2 pb-2", className, background)}
43
+ className={cn(
44
+ "relative h-full min-h-0 px-2 pb-2",
45
+ variant === "web" && "pt-2",
46
+ className,
47
+ background
48
+ )}
44
49
  style={{
45
50
  paddingTop: variant === "desktop" ? TITLE_BAR_HEIGHT : 0,
46
51
  }}
@@ -59,7 +64,7 @@ export function ShellLayout({
59
64
  <AnimatedPanelInset>
60
65
  <header className="flex h-12 flex-row! items-center justify-between gap-2 border-b px-2">
61
66
  {panels?.left?.component && (
62
- <div className="flex min-w-0 flex-1 items-center gap-2">
67
+ <div className="flex min-w-0 shrink-0 items-center justify-start gap-2">
63
68
  <AnimatedPanelTrigger side="left">
64
69
  <MotionIcon name="PanelLeft" size={24} animation="press" />
65
70
  </AnimatedPanelTrigger>
@@ -69,7 +74,7 @@ export function ShellLayout({
69
74
  <div className="flex w-full flex-1 items-center">{header}</div>
70
75
  )}
71
76
  {panels?.right?.component && (
72
- <div className="flex flex-1 items-center justify-end gap-2">
77
+ <div className="flex w-full shrink items-center justify-end gap-2">
73
78
  <AnimatedPanelTrigger aria-label="Toggle panel" side="right">
74
79
  <MotionIcon
75
80
  className="opacity-70"
@@ -12,12 +12,17 @@ export function ComponentPreview({ entry }: { entry: RegistryEntry }) {
12
12
  const Demo = entry.preview
13
13
 
14
14
  return (
15
- <BrowserFrame title={entry.name} titleStyle="hidden" className="min-h-60">
15
+ <BrowserFrame
16
+ title={entry.name}
17
+ titleStyle={entry.titleStyle ?? "expanded"}
18
+ >
16
19
  {Demo ? (
17
20
  <React.Suspense
18
21
  fallback={<p className="text-sm text-muted-foreground">Loading…</p>}
19
22
  >
20
- <Demo />
23
+ <div className="relative h-full min-h-96 w-full">
24
+ <Demo />
25
+ </div>
21
26
  </React.Suspense>
22
27
  ) : (
23
28
  <p className="text-sm text-muted-foreground">
@@ -5,9 +5,11 @@ import {
5
5
  SelectItem,
6
6
  SelectTrigger,
7
7
  SelectValue,
8
- SelectContent} from "@/components/ui/select"
8
+ SelectContent,
9
+ } from "@/components/ui/select"
9
10
  import { Field, FieldLabel } from "@/components/ui/field"
10
- import { Card , CardContent} from "@/components/ui/card";
11
+ import { Card, CardContent } from "@/components/ui/card"
12
+ import { Switch } from "../ui/switch"
11
13
 
12
14
  /**
13
15
  * Lightweight playground controls for registry demos — docs-only, never
@@ -28,22 +30,25 @@ export function DemoSelect<T extends string>({
28
30
  const items = options.map((option) => ({ label: option, value: option }))
29
31
 
30
32
  return (
31
- <Field className="flex flex-col gap-1 text-xs text-muted-foreground">
32
- {label && <FieldLabel>{label}</FieldLabel>}
33
+ <Field className="ml-0 flex w-full flex-1 flex-row items-center justify-between text-muted-foreground">
34
+ {label && <FieldLabel className="ml-0 capitalize">{label}</FieldLabel>}
33
35
  <Select
34
36
  items={items}
35
37
  onValueChange={(next) => onChange(next as T)}
36
38
  value={value}
37
39
  >
38
- <SelectTrigger className="h-7 min-w-0 text-xs capitalize rounded-sm " size="sm">
40
+ <SelectTrigger
41
+ className="h-7 min-w-0 rounded-sm text-xs capitalize"
42
+ size="sm"
43
+ >
39
44
  <SelectValue />
40
45
  </SelectTrigger>
41
46
  <SelectContent>
42
- {items.map((item) => (
43
- <SelectItem key={item.value} value={item.value}>
44
- {item.label}
45
- </SelectItem>
46
- ))}
47
+ {items.map((item) => (
48
+ <SelectItem key={item.value} value={item.value}>
49
+ {item.label}
50
+ </SelectItem>
51
+ ))}
47
52
  </SelectContent>
48
53
  </Select>
49
54
  </Field>
@@ -95,14 +100,15 @@ export function DemoToggle({
95
100
  onChange: (checked: boolean) => void
96
101
  }) {
97
102
  return (
98
- <label className="flex items-center gap-1.5 text-xs text-muted-foreground">
99
- <input
100
- type="checkbox"
101
- checked={checked}
102
- onChange={(event) => onChange(event.target.checked)}
103
- />
104
- {label}
105
- </label>
103
+ <Field className="ml-0 w-full">
104
+ <FieldLabel className="ml-0 w-full justify-between capitalize">
105
+ {label}
106
+ <Switch
107
+ checked={checked}
108
+ onCheckedChange={(value) => onChange(value)}
109
+ />
110
+ </FieldLabel>
111
+ </Field>
106
112
  )
107
113
  }
108
114
 
@@ -118,13 +124,16 @@ export function DemoStage({
118
124
  }) {
119
125
  return (
120
126
  <div className="relative flex w-full flex-col items-center">
121
- {controls && <Card className="absolute top-3 right-3 z-20 rounded-xl shadow-lg">
122
- <CardContent className="flex flex-row items-center gap-x-2">{controls}</CardContent>
123
- </Card>}
127
+ {controls && (
128
+ <Card className="absolute top-3 right-3 z-20 min-w-48 rounded-lg shadow-lg">
129
+ <CardContent className="flex flex-col items-start gap-2">
130
+ {controls}
131
+ </CardContent>
132
+ </Card>
133
+ )}
124
134
  <div
125
135
  className={
126
- canvasClassName ??
127
- "flex min-h-24 max-h-32 w-full items-center justify-center rounded-lg"
136
+ canvasClassName ?? "flex min-h-24 w-full items-center justify-center"
128
137
  }
129
138
  >
130
139
  {children}
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
4
+ import type React from "react";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export function Switch({
8
+ className,
9
+ ...props
10
+ }: SwitchPrimitive.Root.Props): React.ReactElement {
11
+ return (
12
+ <SwitchPrimitive.Root
13
+ className={cn(
14
+ "inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(5)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-disabled:cursor-not-allowed data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(4)]",
15
+ className,
16
+ )}
17
+ data-slot="switch"
18
+ {...props}
19
+ >
20
+ <SwitchPrimitive.Thumb
21
+ className={cn(
22
+ "pointer-events-none block aspect-square h-full origin-left in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:not-data-disabled:scale-x-110 in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s] data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-4px)]",
23
+ )}
24
+ data-slot="switch-thumb"
25
+ />
26
+ </SwitchPrimitive.Root>
27
+ );
28
+ }
29
+
30
+ export { SwitchPrimitive };
package/src/index.ts CHANGED
@@ -60,6 +60,7 @@ export type {
60
60
 
61
61
  // blocks
62
62
  export * from "./components/blocks/auth/auth-shell"
63
+ export * from "./components/blocks/auth/auth-flow-block"
63
64
  export * from "./components/blocks/auth/auth-state"
64
65
  export * from "./components/blocks/auth/code-auth-block"
65
66
  export * from "./components/blocks/auth/forgot-password-block"
@@ -1,19 +0,0 @@
1
- export interface PanelVisibility {
2
- /** How many panels currently fit side by side (1..capacity cap). */
3
- panelCapacity: number;
4
- /** Ids of panels currently hidden (auto + user), for tabs to reflect. */
5
- hiddenPanelIds: readonly string[];
6
- isPanelHidden: (id: string) => boolean;
7
- togglePanelVisibility: (id: string) => void;
8
- /** Id of the panel whose tab is hovered — the canvas spotlights it. */
9
- hoveredPanelId: string | null;
10
- /** @internal Tabs report pointer enter/leave on their label. */
11
- setPanelHovered: (id: string, hovered: boolean) => void;
12
- /** @internal Canvas reports its ordered panel ids each render. */
13
- registerPanelIds: (ids: readonly string[]) => void;
14
- /** @internal Canvas reports its measured width. */
15
- setCanvasWidth: (width: number) => void;
16
- }
17
- /** Owns which panels are hidden as the canvas gains and loses room.
18
- * Lives in `Scaffold.Root`; Canvas and Tab reach it through context. */
19
- export declare function usePanelVisibility(): PanelVisibility;
@@ -1,180 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
-
5
- import { SCAFFOLD_PANEL_CAPACITY } from "./constants"
6
- import { getPanelCapacity } from "./utils"
7
-
8
- /**
9
- * Internal bookkeeping for responsive panel hiding.
10
- *
11
- * - `visibleOrder`: visible panel ids, least-recently-activated first — the
12
- * front is what capacity pressure evicts next.
13
- * - `autoHidden`: panels the scaffold hid because the canvas shrank, most
14
- * recent last. They return on their own when room comes back.
15
- * - `userHidden`: panels hidden by a tab press. They stay hidden until the
16
- * tab is pressed again, however wide the canvas grows.
17
- */
18
- interface PanelVisibilityState {
19
- visibleOrder: string[]
20
- autoHidden: string[]
21
- userHidden: string[]
22
- }
23
-
24
- const EMPTY_STATE: PanelVisibilityState = {
25
- visibleOrder: [],
26
- autoHidden: [],
27
- userHidden: [],
28
- }
29
-
30
- /** Fold the registered ids and current capacity into a settled state:
31
- * prune departed panels, admit new ones, evict the least-recently-activated
32
- * visible panels past capacity, and restore auto-hidden ones when room
33
- * returns. Returns `prev` untouched when nothing changes. */
34
- function reconcile(
35
- prev: PanelVisibilityState,
36
- ids: readonly string[],
37
- capacity: number
38
- ): PanelVisibilityState {
39
- const known = new Set(ids)
40
- const visibleOrder = prev.visibleOrder.filter((id) => known.has(id))
41
- const autoHidden = prev.autoHidden.filter((id) => known.has(id))
42
- const userHidden = prev.userHidden.filter((id) => known.has(id))
43
-
44
- const tracked = new Set([...visibleOrder, ...autoHidden, ...userHidden])
45
- for (const id of ids) if (!tracked.has(id)) visibleOrder.push(id)
46
-
47
- while (visibleOrder.length > capacity && visibleOrder.length > 1) {
48
- autoHidden.push(visibleOrder.shift() as string)
49
- }
50
- while (visibleOrder.length < capacity && autoHidden.length > 0) {
51
- visibleOrder.push(autoHidden.pop() as string)
52
- }
53
-
54
- const unchanged =
55
- visibleOrder.join(" ") === prev.visibleOrder.join(" ") &&
56
- autoHidden.join(" ") === prev.autoHidden.join(" ") &&
57
- userHidden.join(" ") === prev.userHidden.join(" ")
58
- return unchanged ? prev : { visibleOrder, autoHidden, userHidden }
59
- }
60
-
61
- export interface PanelVisibility {
62
- /** How many panels currently fit side by side (1..capacity cap). */
63
- panelCapacity: number
64
- /** Ids of panels currently hidden (auto + user), for tabs to reflect. */
65
- hiddenPanelIds: readonly string[]
66
- isPanelHidden: (id: string) => boolean
67
- togglePanelVisibility: (id: string) => void
68
- /** Id of the panel whose tab is hovered — the canvas spotlights it. */
69
- hoveredPanelId: string | null
70
- /** @internal Tabs report pointer enter/leave on their label. */
71
- setPanelHovered: (id: string, hovered: boolean) => void
72
- /** @internal Canvas reports its ordered panel ids each render. */
73
- registerPanelIds: (ids: readonly string[]) => void
74
- /** @internal Canvas reports its measured width. */
75
- setCanvasWidth: (width: number) => void
76
- }
77
-
78
- /** Owns which panels are hidden as the canvas gains and loses room.
79
- * Lives in `Scaffold.Root`; Canvas and Tab reach it through context. */
80
- export function usePanelVisibility(): PanelVisibility {
81
- const [panelIds, setPanelIds] = React.useState<readonly string[]>([])
82
- const [measuredCapacity, setMeasuredCapacity] = React.useState<number | null>(
83
- null
84
- )
85
- const [state, setState] = React.useState<PanelVisibilityState>(EMPTY_STATE)
86
- const [hoveredPanelId, setHoveredPanelId] = React.useState<string | null>(
87
- null
88
- )
89
-
90
- const panelCapacity = measuredCapacity ?? SCAFFOLD_PANEL_CAPACITY
91
-
92
- const registerPanelIds = React.useCallback((ids: readonly string[]) => {
93
- setPanelIds((prev) =>
94
- prev.length === ids.length && prev.every((id, i) => id === ids[i])
95
- ? prev
96
- : [...ids]
97
- )
98
- }, [])
99
-
100
- // Store the derived capacity, not the raw width — resize storms only
101
- // re-render the tree when a panel actually gains or loses room.
102
- const setCanvasWidth = React.useCallback((width: number) => {
103
- setMeasuredCapacity(getPanelCapacity(width))
104
- }, [])
105
-
106
- // Settle during render (the derive-state-while-rendering pattern): ids
107
- // and capacity arrive as state, so an effect here would only add a
108
- // cascading render after each change.
109
- const settled = reconcile(state, panelIds, panelCapacity)
110
- if (settled !== state) setState(settled)
111
-
112
- const togglePanelVisibility = React.useCallback(
113
- (id: string) => {
114
- setState((prev) => {
115
- if (!panelIds.includes(id)) return prev
116
- const hidden =
117
- prev.autoHidden.includes(id) || prev.userHidden.includes(id)
118
- if (!hidden && prev.visibleOrder.length <= 1) return prev
119
-
120
- const next: PanelVisibilityState = hidden
121
- ? {
122
- // Showing: newest activation — reconcile evicts the oldest
123
- // visible panel if the canvas can't fit one more.
124
- visibleOrder: [...prev.visibleOrder, id],
125
- autoHidden: prev.autoHidden.filter((other) => other !== id),
126
- userHidden: prev.userHidden.filter((other) => other !== id),
127
- }
128
- : {
129
- visibleOrder: prev.visibleOrder.filter((other) => other !== id),
130
- autoHidden: prev.autoHidden,
131
- userHidden: [...prev.userHidden, id],
132
- }
133
- return reconcile(next, panelIds, panelCapacity)
134
- })
135
- },
136
- [panelIds, panelCapacity]
137
- )
138
-
139
- // Leaving clears only its own id — a tab that unmounts mid-hover must
140
- // not wipe out a hover the pointer has already moved on to.
141
- const setPanelHovered = React.useCallback((id: string, hovered: boolean) => {
142
- setHoveredPanelId((prev) => {
143
- if (hovered) return id
144
- return prev === id ? null : prev
145
- })
146
- }, [])
147
-
148
- const hiddenPanelIds = React.useMemo(
149
- () => [...settled.autoHidden, ...settled.userHidden],
150
- [settled]
151
- )
152
-
153
- const isPanelHidden = React.useCallback(
154
- (id: string) => hiddenPanelIds.includes(id),
155
- [hiddenPanelIds]
156
- )
157
-
158
- return React.useMemo(
159
- () => ({
160
- panelCapacity,
161
- hiddenPanelIds,
162
- isPanelHidden,
163
- togglePanelVisibility,
164
- hoveredPanelId,
165
- setPanelHovered,
166
- registerPanelIds,
167
- setCanvasWidth,
168
- }),
169
- [
170
- panelCapacity,
171
- hiddenPanelIds,
172
- isPanelHidden,
173
- togglePanelVisibility,
174
- hoveredPanelId,
175
- setPanelHovered,
176
- registerPanelIds,
177
- setCanvasWidth,
178
- ]
179
- )
180
- }