@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.
- package/dist-lib/components/blocks/auth/__tests__/auth-flow-block.test.d.ts +1 -0
- package/dist-lib/components/blocks/auth/auth-flow-block.d.ts +123 -0
- package/dist-lib/components/blocks/scaffold/__tests__/scaffold-atom.test.d.ts +1 -0
- package/dist-lib/components/blocks/scaffold/index.d.ts +2 -0
- package/dist-lib/components/blocks/scaffold/scaffold-atom.d.ts +97 -0
- package/dist-lib/components/blocks/scaffold/scaffold-context.d.ts +3 -1
- package/dist-lib/components/blocks/scaffold/scaffold-root.d.ts +12 -3
- package/dist-lib/components/blocks/scaffold/type.d.ts +58 -18
- package/dist-lib/components/blocks/scaffold/use-scaffold-state.d.ts +26 -0
- package/dist-lib/components/blocks/scaffold/use-scaffold.d.ts +7 -1
- package/dist-lib/components/blocks/scaffold/utils.d.ts +11 -1
- package/dist-lib/components/ui/switch.d.ts +4 -0
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.js +1683 -1495
- package/dist-lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/beste/piece/browser-frame.tsx +1 -1
- package/src/components/beste/piece/utils.ts +4 -4
- package/src/components/blocks/auth/__tests__/auth-flow-block.test.tsx +183 -0
- package/src/components/blocks/auth/auth-flow-block.tsx +296 -0
- package/src/components/blocks/scaffold/__tests__/scaffold-atom.test.tsx +210 -0
- package/src/components/blocks/scaffold/index.ts +15 -0
- package/src/components/blocks/scaffold/scaffold-actions.tsx +5 -1
- package/src/components/blocks/scaffold/scaffold-atom.ts +383 -0
- package/src/components/blocks/scaffold/scaffold-canvas.tsx +12 -4
- package/src/components/blocks/scaffold/scaffold-context.ts +3 -1
- package/src/components/blocks/scaffold/scaffold-inspector.tsx +9 -2
- package/src/components/blocks/scaffold/scaffold-panel.tsx +24 -10
- package/src/components/blocks/scaffold/scaffold-root.tsx +64 -32
- package/src/components/blocks/scaffold/scaffold-sub-panel.tsx +12 -10
- package/src/components/blocks/scaffold/scaffold-tab.tsx +13 -9
- package/src/components/blocks/scaffold/type.ts +64 -18
- package/src/components/blocks/scaffold/use-scaffold-state.ts +58 -0
- package/src/components/blocks/scaffold/use-scaffold.ts +30 -19
- package/src/components/blocks/scaffold/utils.ts +45 -1
- package/src/components/blocks/shell/shell-layout.tsx +8 -3
- package/src/components/docs/component-preview.tsx +7 -2
- package/src/components/docs/demo-controls.tsx +32 -23
- package/src/components/ui/switch.tsx +30 -0
- package/src/index.ts +1 -0
- package/dist-lib/components/blocks/scaffold/use-panel-visibility.d.ts +0 -19
- package/src/components/blocks/scaffold/use-panel-visibility.ts +0 -180
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SocialProvider } from '../../composed/social-providers';
|
|
2
|
+
import { AuthAccent } from '../../../lib/auth-accent';
|
|
3
|
+
import { CodeAuthBlockProps } from './code-auth-block';
|
|
4
|
+
import { ForgotPasswordBlockProps } from './forgot-password-block';
|
|
5
|
+
import { LoginBlockProps } from './login-block';
|
|
6
|
+
import { OnboardingBlockProps, OnboardingStepConfig, OnboardingValue } from './onboarding-block';
|
|
7
|
+
import { SignupBlockProps } from './signup-block';
|
|
8
|
+
import { UpdatePasswordBlockProps } from './update-password-block';
|
|
9
|
+
import { AuthFlowId, AuthFlowState, AuthFlowStep, AuthUser, BeginAuthVerificationOptions } from './auth-state-type';
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
/**
|
|
12
|
+
* Where the flow goes after a step callback resolves. Returned from every
|
|
13
|
+
* `AuthFlowBlock` handler:
|
|
14
|
+
*
|
|
15
|
+
* - `{ user }` — the attempt signed someone in: mark the flow complete AND
|
|
16
|
+
* sign the session in (one atomic write, `completeAuthFlowAtom`).
|
|
17
|
+
* - `{ verify }` — a code went out: record the identifier and move to the
|
|
18
|
+
* verification step (`beginAuthVerificationAtom`).
|
|
19
|
+
* - `{ step }` — plain navigation with a clean slate (`goToAuthStepAtom`).
|
|
20
|
+
* - `void` — stay put; the block renders its own success state.
|
|
21
|
+
*
|
|
22
|
+
* Rejections are NOT handled here — they propagate back into the block,
|
|
23
|
+
* which owns its transient error/shake state (see `react/CLAUDE.md`,
|
|
24
|
+
* "Third implementation: auth").
|
|
25
|
+
*/
|
|
26
|
+
export type AuthFlowDirective = {
|
|
27
|
+
user: AuthUser;
|
|
28
|
+
} | {
|
|
29
|
+
verify: BeginAuthVerificationOptions;
|
|
30
|
+
} | {
|
|
31
|
+
step: AuthFlowStep;
|
|
32
|
+
} | void;
|
|
33
|
+
export type AuthFlowHandler<Data = void> = (data: Data) => Promise<AuthFlowDirective> | AuthFlowDirective;
|
|
34
|
+
/** Per-step prop overrides, merged over the orchestrator's wiring — spread
|
|
35
|
+
* last, so an app can restyle a block or unhook a default navigation link
|
|
36
|
+
* (`{ login: { onSignup: undefined } }` removes the sign-up hand-off). */
|
|
37
|
+
export interface AuthFlowStepOverrides {
|
|
38
|
+
login?: Partial<LoginBlockProps>;
|
|
39
|
+
signup?: Partial<SignupBlockProps>;
|
|
40
|
+
"verify-code"?: Partial<CodeAuthBlockProps>;
|
|
41
|
+
"forgot-password"?: Partial<ForgotPasswordBlockProps>;
|
|
42
|
+
"update-password"?: Partial<UpdatePasswordBlockProps>;
|
|
43
|
+
onboarding?: Partial<OnboardingBlockProps>;
|
|
44
|
+
}
|
|
45
|
+
export interface AuthFlowBlockProps {
|
|
46
|
+
/** Which flow instance to orchestrate. The default flow unless a re-auth
|
|
47
|
+
* modal or a second surface needs its own. */
|
|
48
|
+
flowId?: AuthFlowId;
|
|
49
|
+
/** Brand mark handed to every step's card. */
|
|
50
|
+
logo?: React.ReactNode;
|
|
51
|
+
/** Brand accent handed to every step's card. */
|
|
52
|
+
accent?: AuthAccent;
|
|
53
|
+
/** Social providers offered on the login and signup steps. */
|
|
54
|
+
providers?: SocialProvider[];
|
|
55
|
+
/** The login attempt. Resolve with a directive; reject to show the error
|
|
56
|
+
* in the block. */
|
|
57
|
+
onLogin?: AuthFlowHandler<{
|
|
58
|
+
email: string;
|
|
59
|
+
password: string;
|
|
60
|
+
remember: boolean;
|
|
61
|
+
}>;
|
|
62
|
+
/** The signup attempt. */
|
|
63
|
+
onSignup?: AuthFlowHandler<{
|
|
64
|
+
name: string;
|
|
65
|
+
email: string;
|
|
66
|
+
password: string;
|
|
67
|
+
}>;
|
|
68
|
+
/** A social provider chosen on the login or signup step. */
|
|
69
|
+
onProviderSelect?: AuthFlowHandler<SocialProvider>;
|
|
70
|
+
/** The forgot-password request. Resolving without a directive stays on the
|
|
71
|
+
* step (the block shows its own "link sent" state). */
|
|
72
|
+
onRequestReset?: AuthFlowHandler<{
|
|
73
|
+
email: string;
|
|
74
|
+
}>;
|
|
75
|
+
/** The code entered on the verification step. */
|
|
76
|
+
onVerifyCode?: AuthFlowHandler<string>;
|
|
77
|
+
/** "Resend code" on the verification step. */
|
|
78
|
+
onResendCode?: AuthFlowHandler;
|
|
79
|
+
/** The update-password submit. */
|
|
80
|
+
onUpdatePassword?: AuthFlowHandler<{
|
|
81
|
+
password: string;
|
|
82
|
+
}>;
|
|
83
|
+
/** Onboarding finished, with the merged profile. */
|
|
84
|
+
onOnboardingComplete?: AuthFlowHandler<Record<string, OnboardingValue>>;
|
|
85
|
+
/** Declared onboarding steps, handed to `OnboardingBlock`. */
|
|
86
|
+
onboardingSteps?: OnboardingStepConfig[];
|
|
87
|
+
/** Per-step prop overrides, merged over the orchestrator's wiring. */
|
|
88
|
+
steps?: AuthFlowStepOverrides;
|
|
89
|
+
/** Replace any step's UI entirely; return `undefined` to keep the default
|
|
90
|
+
* for that step. Receives the flow state for destination copy etc. */
|
|
91
|
+
renderStep?: (step: AuthFlowStep, flow: AuthFlowState) => React.ReactNode | undefined;
|
|
92
|
+
/** Replaces the whole default success card. */
|
|
93
|
+
success?: React.ReactNode;
|
|
94
|
+
/** Card title of the default success step. */
|
|
95
|
+
successTitle?: string;
|
|
96
|
+
/** Body under the default success step's "You're signed in" check. */
|
|
97
|
+
successDescription?: string;
|
|
98
|
+
className?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Renders the right auth block for the flow's current step with the store
|
|
102
|
+
* wiring built in — the switchboard every host app was hand-rolling around
|
|
103
|
+
* `useAuthFlow`. Navigation links between steps (login ↔ signup, forgot
|
|
104
|
+
* password, back from verification) are pre-wired to `goToStep`; each
|
|
105
|
+
* submit-shaped prop awaits your handler and applies the returned
|
|
106
|
+
* {@link AuthFlowDirective}.
|
|
107
|
+
*
|
|
108
|
+
* The blocks themselves stay untouched: passwords, codes and field drafts
|
|
109
|
+
* live in their local state, and a rejected handler renders as the block's
|
|
110
|
+
* own error — the orchestrator never mirrors transients into the store.
|
|
111
|
+
* Needs `ExegiaProvider` above it, like every stateful block.
|
|
112
|
+
*
|
|
113
|
+
* ```tsx
|
|
114
|
+
* <AuthFlowBlock
|
|
115
|
+
* onLogin={async ({ email, password }) => {
|
|
116
|
+
* const outcome = await api.signIn(email, password)
|
|
117
|
+
* return outcome.mfa ? { verify: { identifier: email } } : { user: outcome.user }
|
|
118
|
+
* }}
|
|
119
|
+
* onVerifyCode={async (code) => ({ user: await api.verify(code) })}
|
|
120
|
+
* />
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare function AuthFlowBlock({ flowId, logo, accent, providers, onLogin, onSignup, onProviderSelect, onRequestReset, onVerifyCode, onResendCode, onUpdatePassword, onOnboardingComplete, onboardingSteps, steps, renderStep, success, successTitle, successDescription, className, }: AuthFlowBlockProps): React.ReactElement;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -11,6 +11,8 @@ import { ScaffoldTab } from './scaffold-tab';
|
|
|
11
11
|
import { ScaffoldSubPanel } from './scaffold-sub-panel.tsx';
|
|
12
12
|
export { useScaffoldContext } from './scaffold-context';
|
|
13
13
|
export { useScaffold } from './use-scaffold';
|
|
14
|
+
export { useScaffoldActions, useScaffoldState } from './use-scaffold-state';
|
|
15
|
+
export { removeScaffoldInstance, resetScaffoldAtom, scaffoldHiddenPanelIdsAtom, scaffoldHoveredPanelIdAtom, scaffoldInspectorOpenAtom, scaffoldPanelCapacityAtom, scaffoldPanelDimmedAtom, scaffoldPanelHiddenAtom, scaffoldStateAtom, setScaffoldInspectorOpenAtom, toggleScaffoldInspectorAtom, toggleScaffoldPanelAtom, } from './scaffold-atom';
|
|
14
16
|
export type * from './type';
|
|
15
17
|
export * from './constants';
|
|
16
18
|
export { PanelCloseButton, PanelMenuButton, ScaffoldActions, ScaffoldCanvas, ScaffoldInspector, ScaffoldMain, ScaffoldPanel, ScaffoldRoot, ScaffoldSidebar, ScaffoldTab, };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Atom } from 'jotai';
|
|
2
|
+
import { ScaffoldConfig, ScaffoldHandlers, ScaffoldInstanceId, ScaffoldPanelVisibility, ScaffoldState } from './type';
|
|
3
|
+
type Family<AtomType> = ((id: ScaffoldInstanceId) => AtomType) & {
|
|
4
|
+
remove: (id: ScaffoldInstanceId) => void;
|
|
5
|
+
};
|
|
6
|
+
export declare const scaffoldInspectorOpenAtom: Family<import('jotai').PrimitiveAtom<boolean> & {
|
|
7
|
+
init: boolean;
|
|
8
|
+
}>;
|
|
9
|
+
/** @internal The canvas's ordered panel ids, as registered each render. */
|
|
10
|
+
export declare const scaffoldPanelIdsAtom: Family<import('jotai').PrimitiveAtom<readonly string[]> & {
|
|
11
|
+
init: readonly string[];
|
|
12
|
+
}>;
|
|
13
|
+
/** @internal The capacity derived from the canvas's measured width — the
|
|
14
|
+
* derived number is stored, not the raw width, so resize storms only touch
|
|
15
|
+
* the store when a panel actually gains or loses room. */
|
|
16
|
+
export declare const scaffoldMeasuredCapacityAtom: Family<import('jotai').PrimitiveAtom<number | null> & {
|
|
17
|
+
init: number | null;
|
|
18
|
+
}>;
|
|
19
|
+
/** @internal The three visibility lists, settled as one value. */
|
|
20
|
+
export declare const scaffoldVisibilityAtom: Family<import('jotai').PrimitiveAtom<ScaffoldPanelVisibility> & {
|
|
21
|
+
init: ScaffoldPanelVisibility;
|
|
22
|
+
}>;
|
|
23
|
+
export declare const scaffoldHoveredPanelIdAtom: Family<import('jotai').PrimitiveAtom<string | null> & {
|
|
24
|
+
init: string | null;
|
|
25
|
+
}>;
|
|
26
|
+
/** @internal */
|
|
27
|
+
export declare const scaffoldConfigAtom: Family<import('jotai').PrimitiveAtom<ScaffoldConfig> & {
|
|
28
|
+
init: ScaffoldConfig;
|
|
29
|
+
}>;
|
|
30
|
+
/** @internal */
|
|
31
|
+
export declare const scaffoldHandlersAtom: Family<import('jotai').PrimitiveAtom<ScaffoldHandlers> & {
|
|
32
|
+
init: ScaffoldHandlers;
|
|
33
|
+
}>;
|
|
34
|
+
/** How many panels fit side by side; the cap while the canvas is unmeasured. */
|
|
35
|
+
export declare const scaffoldPanelCapacityAtom: Family<Atom<number>>;
|
|
36
|
+
/** Ids of panels currently hidden (auto + user), for tabs to reflect. */
|
|
37
|
+
export declare const scaffoldHiddenPanelIdsAtom: Family<Atom<readonly string[]>>;
|
|
38
|
+
/** Whether one panel is hidden. A tab subscribes here and sits still while
|
|
39
|
+
* its siblings toggle. Empty `panelId` (a tab without one) reads false. */
|
|
40
|
+
export declare const scaffoldPanelHiddenAtom: (id: ScaffoldInstanceId, panelId: string) => Atom<boolean>;
|
|
41
|
+
/** Whether one panel fades back while another panel's tab holds the
|
|
42
|
+
* spotlight. Moving the hover between two tabs re-renders those panels
|
|
43
|
+
* only — everyone else's boolean holds. */
|
|
44
|
+
export declare const scaffoldPanelDimmedAtom: (id: ScaffoldInstanceId, panelId: string) => Atom<boolean>;
|
|
45
|
+
/** The whole state of one scaffold. This changes on every hover move, so a
|
|
46
|
+
* component that reads one field should subscribe to that field's atom
|
|
47
|
+
* instead: `useAtomValue(scaffoldInspectorOpenAtom("workspace"))`. */
|
|
48
|
+
export declare const scaffoldStateAtom: Family<Atom<ScaffoldState>>;
|
|
49
|
+
/** Reports through `onInspectorOpenChange` always; writes the store only
|
|
50
|
+
* when no `inspectorOpen` prop controls the root — the prop is truth then. */
|
|
51
|
+
export declare const setScaffoldInspectorOpenAtom: Family<import('jotai').WritableAtom<null, [open: boolean], void> & {
|
|
52
|
+
init: null;
|
|
53
|
+
}>;
|
|
54
|
+
export declare const toggleScaffoldInspectorAtom: Family<import('jotai').WritableAtom<null, [], void> & {
|
|
55
|
+
init: null;
|
|
56
|
+
}>;
|
|
57
|
+
/** Show/hide an id'd panel. Showing past capacity auto-hides the
|
|
58
|
+
* least-recently-activated visible panel; the last visible one never hides. */
|
|
59
|
+
export declare const toggleScaffoldPanelAtom: Family<import('jotai').WritableAtom<null, [panelId: string], void> & {
|
|
60
|
+
init: null;
|
|
61
|
+
}>;
|
|
62
|
+
/** @internal Tabs report pointer enter/leave on their label. Leaving clears
|
|
63
|
+
* only its own id — a tab that unmounts mid-hover must not wipe out a hover
|
|
64
|
+
* the pointer has already moved on to. */
|
|
65
|
+
export declare const setScaffoldPanelHoveredAtom: Family<import('jotai').WritableAtom<null, [panelId: string, hovered: boolean], void> & {
|
|
66
|
+
init: null;
|
|
67
|
+
}>;
|
|
68
|
+
/** @internal Canvas reports its ordered panel ids each render. Inert when
|
|
69
|
+
* the ids did not move; otherwise the visibility settles in the same write. */
|
|
70
|
+
export declare const registerScaffoldPanelIdsAtom: Family<import('jotai').WritableAtom<null, [ids: readonly string[]], void> & {
|
|
71
|
+
init: null;
|
|
72
|
+
}>;
|
|
73
|
+
/** @internal Canvas reports its measured width. Only the derived capacity is
|
|
74
|
+
* stored, so resize storms settle to at most one visibility change. */
|
|
75
|
+
export declare const measureScaffoldCanvasAtom: Family<import('jotai').WritableAtom<null, [width: number], void> & {
|
|
76
|
+
init: null;
|
|
77
|
+
}>;
|
|
78
|
+
/** @internal Projection of the mounted root's controlled props. */
|
|
79
|
+
export declare const projectScaffoldPropsAtom: Family<import('jotai').WritableAtom<null, [config: ScaffoldConfig, inspectorOpen: boolean | undefined], void> & {
|
|
80
|
+
init: null;
|
|
81
|
+
}>;
|
|
82
|
+
/** @internal */
|
|
83
|
+
export declare const setScaffoldHandlersAtom: Family<import('jotai').WritableAtom<null, [handlers: ScaffoldHandlers], void> & {
|
|
84
|
+
init: null;
|
|
85
|
+
}>;
|
|
86
|
+
/** @internal Seed the uncontrolled inspector on mount without firing
|
|
87
|
+
* `onInspectorOpenChange`. */
|
|
88
|
+
export declare const seedScaffoldInspectorAtom: Family<import('jotai').WritableAtom<null, [open: boolean], void> & {
|
|
89
|
+
init: null;
|
|
90
|
+
}>;
|
|
91
|
+
export declare const resetScaffoldAtom: Family<import('jotai').WritableAtom<null, [], void> & {
|
|
92
|
+
init: null;
|
|
93
|
+
}>;
|
|
94
|
+
/** Forget a scaffold entirely — every family drops the key so the store can
|
|
95
|
+
* release its state. Call on teardown of a named instance. */
|
|
96
|
+
export declare function removeScaffoldInstance(id: ScaffoldInstanceId): void;
|
|
97
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ScaffoldContextValue } from './type';
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
export declare const ScaffoldContext: React.Context<ScaffoldContextValue | null>;
|
|
4
|
-
/** Read the scaffold's
|
|
4
|
+
/** Read the scaffold's identity (`scaffoldId`, `inspectorWidth`); must run
|
|
5
|
+
* under `Scaffold.Root`. State itself lives in the store — subscribe to the
|
|
6
|
+
* atoms, or reach them by id through `useScaffoldState` / `useScaffoldActions`. */
|
|
5
7
|
export declare function useScaffoldContext(): ScaffoldContextValue;
|
|
@@ -2,7 +2,16 @@ import { ScaffoldRootProps } from './type';
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
/**
|
|
4
4
|
* The scaffold's viewport: desktop backdrop + horizontal row of rail and
|
|
5
|
-
* main region, and the
|
|
6
|
-
* container — size it from the outside (e.g.
|
|
5
|
+
* main region, and the binding between this instance's props and its slice
|
|
6
|
+
* of the store. Fills its container — size it from the outside (e.g.
|
|
7
|
+
* `h-svh` for a full page).
|
|
8
|
+
*
|
|
9
|
+
* State lives in the store under `scaffoldId`; the context carries only the
|
|
10
|
+
* id and the drawer width, so its value never changes while the scaffold is
|
|
11
|
+
* mounted and parts subscribe to exactly the atoms they render from. A
|
|
12
|
+
* controlled `inspectorOpen` stays the source of truth: it is projected
|
|
13
|
+
* one-way into the store (so remote readers see current data), and the
|
|
14
|
+
* inspector actions report through `onInspectorOpenChange` instead of
|
|
15
|
+
* writing.
|
|
7
16
|
*/
|
|
8
|
-
export declare function ScaffoldRoot({ inspectorOpen: inspectorOpenProp, defaultInspectorOpen, onInspectorOpenChange, inspectorWidth, className, children, ...rest }: ScaffoldRootProps): React.ReactElement;
|
|
17
|
+
export declare function ScaffoldRoot({ scaffoldId: scaffoldIdProp, inspectorOpen: inspectorOpenProp, defaultInspectorOpen, onInspectorOpenChange, inspectorWidth, className, children, ...rest }: ScaffoldRootProps): React.ReactElement;
|
|
@@ -1,35 +1,69 @@
|
|
|
1
1
|
import { default as React, ComponentProps, ReactElement, ReactNode } from 'react';
|
|
2
|
-
/**
|
|
2
|
+
/** Key of one scaffold's slice of the store. */
|
|
3
|
+
export type ScaffoldInstanceId = string;
|
|
4
|
+
/** The identity every scaffold part shares through ScaffoldContext. State
|
|
5
|
+
* itself lives in the store — parts subscribe to the atoms they render from,
|
|
6
|
+
* so this value never changes identity while the scaffold is mounted. */
|
|
3
7
|
export interface ScaffoldContextValue {
|
|
4
|
-
|
|
5
|
-
inspectorOpen: boolean;
|
|
8
|
+
scaffoldId: ScaffoldInstanceId;
|
|
6
9
|
/** Drawer width in px — Actions reads it to slide out of the drawer's way. */
|
|
7
10
|
inspectorWidth: number;
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
}
|
|
12
|
+
/** One scaffold's whole state, as `useScaffoldState` returns it. A component
|
|
13
|
+
* that watches one field should subscribe to that field's atom instead. */
|
|
14
|
+
export interface ScaffoldState {
|
|
15
|
+
/** Whether the inspector drawer is currently shown. */
|
|
16
|
+
inspectorOpen: boolean;
|
|
10
17
|
/** How many panels currently fit side by side, from the measured canvas
|
|
11
18
|
* width at `SCAFFOLD_PANEL_MIN_WIDTH` per panel (1..`SCAFFOLD_PANEL_CAPACITY`). */
|
|
12
19
|
panelCapacity: number;
|
|
13
20
|
/** Ids of id'd panels the scaffold is currently hiding — auto-hidden by
|
|
14
21
|
* capacity pressure or toggled away from a tab. */
|
|
15
22
|
hiddenPanelIds: readonly string[];
|
|
16
|
-
isPanelHidden: (id: string) => boolean;
|
|
17
|
-
/** Show/hide an id'd panel. Showing past capacity auto-hides the
|
|
18
|
-
* least-recently-activated visible panel; the last visible one never hides. */
|
|
19
|
-
togglePanelVisibility: (id: string) => void;
|
|
20
23
|
/** Id of the panel whose tab the pointer is resting on — the canvas
|
|
21
24
|
* spotlights it by fading every other id'd panel to 0.35 opacity. */
|
|
22
25
|
hoveredPanelId: string | null;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
}
|
|
27
|
+
/** Drive a scaffold by id from anywhere, as `useScaffoldActions` returns it. */
|
|
28
|
+
export interface ScaffoldStateActions {
|
|
29
|
+
setInspectorOpen: (open: boolean) => void;
|
|
30
|
+
toggleInspector: () => void;
|
|
31
|
+
/** Show/hide an id'd panel. Showing past capacity auto-hides the
|
|
32
|
+
* least-recently-activated visible panel; the last visible one never hides. */
|
|
33
|
+
togglePanel: (panelId: string) => void;
|
|
34
|
+
reset: () => void;
|
|
35
|
+
}
|
|
36
|
+
/** @internal Which props currently control the scaffold — write gates for
|
|
37
|
+
* the action atoms, so the store never overwrites a prop. */
|
|
38
|
+
export interface ScaffoldConfig {
|
|
39
|
+
controlsInspector: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** @internal The mounted root's callbacks, published into the store so
|
|
42
|
+
* action atoms can report changes wherever they were fired from. */
|
|
43
|
+
export interface ScaffoldHandlers {
|
|
44
|
+
onInspectorOpenChange?: (open: boolean) => void;
|
|
45
|
+
}
|
|
46
|
+
/** @internal Bookkeeping for responsive panel hiding.
|
|
47
|
+
* - `visibleOrder`: visible panel ids, least-recently-activated first — the
|
|
48
|
+
* front is what capacity pressure evicts next.
|
|
49
|
+
* - `autoHidden`: panels the scaffold hid because the canvas shrank, most
|
|
50
|
+
* recent last. They return on their own when room comes back.
|
|
51
|
+
* - `userHidden`: panels hidden by a tab press. They stay hidden until the
|
|
52
|
+
* tab is pressed again, however wide the canvas grows. */
|
|
53
|
+
export interface ScaffoldPanelVisibility {
|
|
54
|
+
visibleOrder: string[];
|
|
55
|
+
autoHidden: string[];
|
|
56
|
+
userHidden: string[];
|
|
29
57
|
}
|
|
30
58
|
export interface ScaffoldRootProps extends ComponentProps<"div"> {
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
59
|
+
/** Names this scaffold's slice of the store, so `useScaffoldState` /
|
|
60
|
+
* `useScaffoldActions` can drive it by id and its state outlives the
|
|
61
|
+
* component. Omitted, the root keys off `useId` and drops its state on
|
|
62
|
+
* unmount. `useScaffold().providerProps` carries one. */
|
|
63
|
+
scaffoldId?: ScaffoldInstanceId;
|
|
64
|
+
/** Controlled inspector state — pair with `onInspectorOpenChange`. The
|
|
65
|
+
* prop stays the source of truth: store writes are gated off, and actions
|
|
66
|
+
* report through the callback instead. */
|
|
33
67
|
inspectorOpen?: boolean;
|
|
34
68
|
/** Initial inspector state when uncontrolled. Closed by default. */
|
|
35
69
|
defaultInspectorOpen?: boolean;
|
|
@@ -148,16 +182,22 @@ export interface PanelMenuButtonProps extends PanelFloatingButtonProps {
|
|
|
148
182
|
swapped?: boolean;
|
|
149
183
|
}
|
|
150
184
|
export interface UseScaffoldOptions {
|
|
185
|
+
/** Names the scaffold's slice of the store. Omitted, the hook generates
|
|
186
|
+
* one and drops its state on unmount. */
|
|
187
|
+
scaffoldId?: ScaffoldInstanceId;
|
|
151
188
|
/** Initial inspector state. Closed by default. */
|
|
152
189
|
defaultInspectorOpen?: boolean;
|
|
153
190
|
/** Fires on every inspector open/close. */
|
|
154
191
|
onInspectorChange?: (open: boolean) => void;
|
|
155
192
|
}
|
|
156
193
|
export interface ScaffoldControls {
|
|
194
|
+
/** The id the hook and the root share — hand it to `useScaffoldState` /
|
|
195
|
+
* `useScaffoldActions` to drive the scaffold from elsewhere. */
|
|
196
|
+
scaffoldId: ScaffoldInstanceId;
|
|
157
197
|
inspectorOpen: boolean;
|
|
158
198
|
setInspectorOpen: (open: boolean) => void;
|
|
159
199
|
toggleInspector: () => void;
|
|
160
200
|
/** Spread onto Scaffold.Root. */
|
|
161
|
-
providerProps: Pick<ScaffoldRootProps, "
|
|
201
|
+
providerProps: Pick<ScaffoldRootProps, "scaffoldId" | "defaultInspectorOpen" | "onInspectorOpenChange">;
|
|
162
202
|
}
|
|
163
203
|
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ScaffoldInstanceId, ScaffoldState, ScaffoldStateActions } from './type';
|
|
2
|
+
/**
|
|
3
|
+
* Read the scaffold registered under `scaffoldId` from anywhere below
|
|
4
|
+
* `ExegiaProvider` — no controller, no props, no provider of its own.
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* const { inspectorOpen, hiddenPanelIds } = useScaffoldState("workspace")
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* This returns the whole state object, so the caller re-renders on every
|
|
11
|
+
* change, hovers included. A component that reads one field should subscribe
|
|
12
|
+
* to that field's atom instead:
|
|
13
|
+
* `useAtomValue(scaffoldInspectorOpenAtom("workspace"))`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useScaffoldState(scaffoldId: ScaffoldInstanceId): ScaffoldState;
|
|
16
|
+
/**
|
|
17
|
+
* Drive the scaffold registered under `scaffoldId` from anywhere. Writes
|
|
18
|
+
* only — the caller never re-renders when the scaffold changes, so this is
|
|
19
|
+
* what a command palette or a keyboard shortcut should reach for.
|
|
20
|
+
*
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const scaffold = useScaffoldActions("workspace")
|
|
23
|
+
* <Button onClick={scaffold.toggleInspector}>Inspect</Button>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function useScaffoldActions(scaffoldId: ScaffoldInstanceId): ScaffoldStateActions;
|
|
@@ -4,5 +4,11 @@ import { ScaffoldControls, UseScaffoldOptions } from './type';
|
|
|
4
4
|
* (title-bar buttons, command palette, shortcuts). Spread the returned
|
|
5
5
|
* `providerProps` onto `Scaffold.Root`; without this hook the root manages
|
|
6
6
|
* the same state internally via `defaultInspectorOpen`.
|
|
7
|
+
*
|
|
8
|
+
* The hook and the root meet in the store: `providerProps` carries a
|
|
9
|
+
* `scaffoldId`, both sides read and write that instance's atoms, and
|
|
10
|
+
* `useScaffoldState` / `useScaffoldActions` reach the same slice from
|
|
11
|
+
* anywhere else by id. Unnamed scaffolds key off `useId` and are dropped on
|
|
12
|
+
* unmount; an explicit `scaffoldId` outlives its component.
|
|
7
13
|
*/
|
|
8
|
-
export declare function useScaffold({ defaultInspectorOpen, onInspectorChange, }?: UseScaffoldOptions): ScaffoldControls;
|
|
14
|
+
export declare function useScaffold({ scaffoldId: scaffoldIdProp, defaultInspectorOpen, onInspectorChange, }?: UseScaffoldOptions): ScaffoldControls;
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Variants } from 'motion/react';
|
|
2
2
|
import { ClassNameValue } from 'tailwind-merge';
|
|
3
|
-
import { TSubPanelVariant } from './type.ts';
|
|
3
|
+
import { ScaffoldPanelVisibility, TSubPanelVariant } from './type.ts';
|
|
4
4
|
/**
|
|
5
5
|
* How many panels fit on a canvas of `width` px, granting each
|
|
6
6
|
* `SCAFFOLD_PANEL_MIN_WIDTH` plus the gaps between them. Clamped to
|
|
7
7
|
* [1, SCAFFOLD_PANEL_CAPACITY]; an unmeasured canvas (`null`) fits the cap.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getPanelCapacity(width: number | null): number;
|
|
10
|
+
/** @internal An untracked scaffold: nothing registered, nothing hidden. */
|
|
11
|
+
export declare const EMPTY_SCAFFOLD_VISIBILITY: ScaffoldPanelVisibility;
|
|
12
|
+
/**
|
|
13
|
+
* @internal Fold the registered ids and current capacity into a settled
|
|
14
|
+
* visibility: prune departed panels, admit new ones, evict the
|
|
15
|
+
* least-recently-activated visible panels past capacity, and restore
|
|
16
|
+
* auto-hidden ones when room returns. Returns `prev` untouched when nothing
|
|
17
|
+
* changes, so callers can compare identities instead of contents.
|
|
18
|
+
*/
|
|
19
|
+
export declare function reconcileVisibility(prev: ScaffoldPanelVisibility, ids: readonly string[], capacity: number): ScaffoldPanelVisibility;
|
|
10
20
|
/** Desktop backdrop the whole scaffold sits on — a soft warm-gray wash. */
|
|
11
21
|
export declare const scaffoldBackgroundClass: ClassNameValue;
|
|
12
22
|
/** Card surface shared by a panel's primary area and secondary strip. */
|
package/dist-lib/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * from './components/composed/tree';
|
|
|
27
27
|
export { DEFAULT_BEZEL_ANGLE, PresenceBadge, UserAvatar, initialsFrom, removeUserAvatarInstance, resetUserAvatarAtom, setUserAvatarBezelAngleAtom, setUserAvatarPresenceAtom, toggleUserAvatarPresenceAtom, useUserAvatar, useUserAvatarActions, useUserAvatarState, userAvatarBezelAngleAtom, userAvatarIsOnlineAtom, userAvatarPresenceAtom, userAvatarStateAtom, } from './components/user-avatar';
|
|
28
28
|
export type { UseUserAvatarOptions, UserAvatarActions, UserAvatarBinding, UserAvatarInstanceId, UserAvatarProps, UserAvatarState, UserPresence, } from './components/user-avatar';
|
|
29
29
|
export * from './components/blocks/auth/auth-shell';
|
|
30
|
+
export * from './components/blocks/auth/auth-flow-block';
|
|
30
31
|
export * from './components/blocks/auth/auth-state';
|
|
31
32
|
export * from './components/blocks/auth/code-auth-block';
|
|
32
33
|
export * from './components/blocks/auth/forgot-password-block';
|