@xenosystem/blocks 0.10.1 → 0.11.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/auth/index.d.ts +105 -5
- package/dist/auth/index.js +402 -212
- package/dist/time/index.js +47 -209
- package/package.json +3 -3
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { PanelModule, PanelManifest, BlockDeclaration } from '@xenosystem/block-sdk';
|
|
4
|
+
import { PanelTone } from '@xenosystem/components/chrome';
|
|
4
5
|
|
|
5
6
|
interface CreateAuthGatePanelOptions {
|
|
6
7
|
/** What renders behind the gate once it is `open`. A product passes its app; the harness a fixture. */
|
|
@@ -371,9 +372,6 @@ declare function plateCopy(phase: XenoAuthGatePhase, product: string, message: s
|
|
|
371
372
|
body: string;
|
|
372
373
|
note?: string;
|
|
373
374
|
};
|
|
374
|
-
declare const BEHAVIOURS: {
|
|
375
|
-
'auth/authGateView': (inputs: Record<string, unknown>, config: Readonly<Record<string, unknown>>) => AuthGateView;
|
|
376
|
-
};
|
|
377
375
|
|
|
378
376
|
/**
|
|
379
377
|
* `mountXenoAuthGate` — the per-product plug, exactly as `XENO AUTH - AUTH GATE DELTA.md` §4 specifies:
|
|
@@ -611,7 +609,109 @@ interface AccountPanelViewProps {
|
|
|
611
609
|
showEntitlements?: boolean;
|
|
612
610
|
emptyHint?: string;
|
|
613
611
|
}
|
|
614
|
-
/**
|
|
612
|
+
/**
|
|
613
|
+
* The Account panel view — the code twin of `ACCOUNT_DECLARATION`, rendering the SAME model
|
|
614
|
+
* (`accountPanelView`) so the two cannot drift; `test/auth-account/declaration.test.tsx` holds the markup
|
|
615
|
+
* byte-identical in every status.
|
|
616
|
+
*/
|
|
615
617
|
declare function AccountPanelView({ controller, showLedger, showEntitlements, emptyHint, }: AccountPanelViewProps): ReactNode;
|
|
616
618
|
|
|
617
|
-
|
|
619
|
+
/**
|
|
620
|
+
* The account panel AS A DECLARATION — the third block written the §8d way (auth gate, agent, account).
|
|
621
|
+
* Chrome units + bindings + emits over ONE behaviour, `auth/accountPanelView`, which derives every label,
|
|
622
|
+
* tone and row shape from `AccountViewState`. The code view renders the same model; the test holds the
|
|
623
|
+
* two byte-identical in every account status.
|
|
624
|
+
*
|
|
625
|
+
* Presentation contract: input `view` (an `AccountViewState` push from the controller), output `ui`
|
|
626
|
+
* (`{ kind, seatId?, expanded? }`), applied by the controller (`request(kind)`, `refresh()`,
|
|
627
|
+
* `setLedgerExpanded()`). The declaration holds no state.
|
|
628
|
+
*/
|
|
629
|
+
|
|
630
|
+
type AccountUiIntent = {
|
|
631
|
+
kind: 'signIn';
|
|
632
|
+
} | {
|
|
633
|
+
kind: 'signOut';
|
|
634
|
+
} | {
|
|
635
|
+
kind: 'manageBilling';
|
|
636
|
+
} | {
|
|
637
|
+
kind: 'refresh';
|
|
638
|
+
} | {
|
|
639
|
+
kind: 'switchSeat';
|
|
640
|
+
seatId: string;
|
|
641
|
+
} | {
|
|
642
|
+
kind: 'ledgerCollapsed';
|
|
643
|
+
collapsed: boolean;
|
|
644
|
+
};
|
|
645
|
+
declare const accountViewManifest: PanelManifest;
|
|
646
|
+
declare const STATUS_LABEL: Record<XenoAccountStatus, string>;
|
|
647
|
+
declare const STATUS_TONE: Record<XenoAccountStatus, PanelTone>;
|
|
648
|
+
interface AccountPanelViewModel {
|
|
649
|
+
loading: boolean;
|
|
650
|
+
signedOut: boolean;
|
|
651
|
+
signedIn: boolean;
|
|
652
|
+
loadingHint: string;
|
|
653
|
+
statusLabel: string;
|
|
654
|
+
statusTone: PanelTone;
|
|
655
|
+
signedOutHint: string;
|
|
656
|
+
planLabel?: string;
|
|
657
|
+
planTitle?: string;
|
|
658
|
+
name?: string;
|
|
659
|
+
email?: string;
|
|
660
|
+
message?: string;
|
|
661
|
+
hasCredits: boolean;
|
|
662
|
+
creditsUnit: string;
|
|
663
|
+
creditsBalance: string;
|
|
664
|
+
creditsSub?: string;
|
|
665
|
+
creditsStale: boolean;
|
|
666
|
+
creditsTitle: string;
|
|
667
|
+
hasIncluded: boolean;
|
|
668
|
+
includedValue: string;
|
|
669
|
+
includedSub?: string;
|
|
670
|
+
showSeats: boolean;
|
|
671
|
+
seats: {
|
|
672
|
+
id: string;
|
|
673
|
+
label: string;
|
|
674
|
+
active: boolean;
|
|
675
|
+
inactive: boolean;
|
|
676
|
+
}[];
|
|
677
|
+
showEntitlements: boolean;
|
|
678
|
+
entitlements: {
|
|
679
|
+
id: string;
|
|
680
|
+
label: string;
|
|
681
|
+
detail?: string;
|
|
682
|
+
tone: PanelTone;
|
|
683
|
+
text: string;
|
|
684
|
+
}[];
|
|
685
|
+
showLedger: boolean;
|
|
686
|
+
ledgerCollapsed: boolean;
|
|
687
|
+
ledgerCount?: string;
|
|
688
|
+
hasLedger: boolean;
|
|
689
|
+
ledgerEmpty: boolean;
|
|
690
|
+
ledger: {
|
|
691
|
+
id: string;
|
|
692
|
+
description: string;
|
|
693
|
+
source?: string;
|
|
694
|
+
amount: string;
|
|
695
|
+
}[];
|
|
696
|
+
ledgerHasMore: boolean;
|
|
697
|
+
renews?: string;
|
|
698
|
+
offlineNote?: string;
|
|
699
|
+
}
|
|
700
|
+
interface AccountPanelViewOptions {
|
|
701
|
+
showLedger?: boolean;
|
|
702
|
+
showEntitlements?: boolean;
|
|
703
|
+
emptyHint?: string;
|
|
704
|
+
}
|
|
705
|
+
declare function accountPanelView(state: AccountViewState, options?: AccountPanelViewOptions): AccountPanelViewModel;
|
|
706
|
+
declare const BEHAVIOURS$1: {
|
|
707
|
+
'auth/accountPanelView': (inputs: Record<string, unknown>, config: Readonly<Record<string, unknown>>) => AccountPanelViewModel;
|
|
708
|
+
};
|
|
709
|
+
declare const ACCOUNT_DECLARATION: BlockDeclaration;
|
|
710
|
+
|
|
711
|
+
/** Every behaviour of the auth family — the gate's and the account's — for a host's block registry. */
|
|
712
|
+
declare const BEHAVIOURS: {
|
|
713
|
+
'auth/accountPanelView': (inputs: Record<string, unknown>, config: Readonly<Record<string, unknown>>) => AccountPanelViewModel;
|
|
714
|
+
'auth/authGateView': (inputs: Record<string, unknown>, config: Readonly<Record<string, unknown>>) => AuthGateView;
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
export { BEHAVIOURS$1 as ACCOUNT_BEHAVIOURS, ACCOUNT_DECLARATION, ACCOUNT_PANEL_ID, AUTH_GATE_DECLARATION, AUTH_GATE_INITIAL, AUTH_GATE_PANEL_ID, AccountController, type AccountControllerOptions, type AccountHostBridge, type AccountPanelState, AccountPanelView, type AccountPanelViewModel, type AccountPanelViewOptions, type AccountPanelViewProps, type AccountRenderContext, type AccountUiIntent, type AccountViewState, type AuthGateAction, AuthGateController, type AuthGateHostBridge, AuthGateView$1 as AuthGateView, type AuthGateView as AuthGateViewModel, type AuthGateViewProps, BEHAVIOURS, type CreateAccountPanelOptions, type CreateAuthGatePanelOptions, type MountXenoAuthGateOptions, type MountedXenoAuthGate, PHASE_INTENTS, STATUS_LABEL, STATUS_TONE, STEP_UP_ACTIONS, type XenoAccountAction, type XenoAccountActionKind, type XenoAccountCredits, type XenoAccountIdentity, type XenoAccountPlan, type XenoAccountState, type XenoAccountStatus, type XenoAuthGateBridge, type XenoAuthGateIntent, type XenoAuthGateIntentKind, type XenoAuthGatePhase, type XenoAuthGateState, type XenoEntitlement, type XenoLedgerDelta, type XenoLedgerEntry, type XenoLicenceState, accountManifest, accountPanel, accountPanelView, accountViewManifest, authGateManifest, authGatePanel, authGateView, createAccountPanel, createAuthGatePanel, creditsAge, deriveAuthGatePhase, formatAge, formatAmount, formatSince, hostContradiction, intentOffered, isSignedIn, mountXenoAuthGate, plateCopy, requiresStepUp };
|
package/dist/auth/index.js
CHANGED
|
@@ -318,6 +318,365 @@ var AUTH_GATE_DECLARATION = {
|
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
320
|
|
|
321
|
+
// src/auth/account/manifest.ts
|
|
322
|
+
import { WELL_KNOWN_PORT_SCHEMAS } from "@xenosystem/block-sdk";
|
|
323
|
+
var ACCOUNT_PANEL_ID = "xeno.core.account";
|
|
324
|
+
var accountManifest = {
|
|
325
|
+
id: ACCOUNT_PANEL_ID,
|
|
326
|
+
version: "0.1.0",
|
|
327
|
+
title: "Account",
|
|
328
|
+
icon: "user-round",
|
|
329
|
+
description: "Identity, plan, credits, entitlements and ledger \u2014 all host-pushed, never fetched. Balances carry the moment they were true. Sensitive actions are emitted as step-up intents, never performed.",
|
|
330
|
+
defaultSlot: "inspector",
|
|
331
|
+
inputs: [
|
|
332
|
+
{
|
|
333
|
+
id: "account",
|
|
334
|
+
name: "Account",
|
|
335
|
+
type: "object",
|
|
336
|
+
schema: WELL_KNOWN_PORT_SCHEMAS.ACCOUNT,
|
|
337
|
+
description: "{status, identity?, plan?, credits?, entitlements?, seats?, message?}. The host is authoritative. Contains NO token \u2014 see AUTH L9.",
|
|
338
|
+
multiple: false
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
id: "ledger",
|
|
342
|
+
name: "Ledger",
|
|
343
|
+
type: "object",
|
|
344
|
+
schema: WELL_KNOWN_PORT_SCHEMAS.LEDGER,
|
|
345
|
+
description: "{rev?, append?, replace?, clear?, hasMore?}. Append-oriented; `rev` gates out-of-order deliveries.",
|
|
346
|
+
multiple: true
|
|
347
|
+
}
|
|
348
|
+
],
|
|
349
|
+
outputs: [
|
|
350
|
+
{
|
|
351
|
+
id: "action",
|
|
352
|
+
name: "Action",
|
|
353
|
+
type: "object",
|
|
354
|
+
schema: WELL_KNOWN_PORT_SCHEMAS.ACCOUNT_ACTION,
|
|
355
|
+
description: "{kind, seatId?, productId?, stepUp?}. An INTENT. `stepUp: true` marks an action AUTH L12 requires a fresh interactive re-auth for; the host must not satisfy it silently from the broker."
|
|
356
|
+
}
|
|
357
|
+
],
|
|
358
|
+
commands: [
|
|
359
|
+
{
|
|
360
|
+
id: "refresh",
|
|
361
|
+
title: "Refresh",
|
|
362
|
+
description: "Ask the host to re-read the balance. Idempotent; no step-up.",
|
|
363
|
+
parameters: {}
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
id: "get_account",
|
|
367
|
+
title: "Get Account",
|
|
368
|
+
description: "Return the rendered account state \u2014 status, plan, balance and its asOf. Never a token.",
|
|
369
|
+
parameters: {}
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "get_ledger",
|
|
373
|
+
title: "Get Ledger",
|
|
374
|
+
description: "Return the held ledger entries, newest first.",
|
|
375
|
+
parameters: {}
|
|
376
|
+
}
|
|
377
|
+
// NOTE: `signOut`, `purchase` and `manageBilling` are deliberately NOT commands. They require a
|
|
378
|
+
// fresh interactive re-auth (AUTH L12), and an agent-invocable command is by definition not
|
|
379
|
+
// interactive. Exposing them would make this panel the bypass for the step-up requirement.
|
|
380
|
+
],
|
|
381
|
+
config: [
|
|
382
|
+
{
|
|
383
|
+
key: "showLedger",
|
|
384
|
+
label: "Show ledger",
|
|
385
|
+
type: "boolean",
|
|
386
|
+
defaultValue: true,
|
|
387
|
+
description: "Show recent credit activity."
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
key: "showEntitlements",
|
|
391
|
+
label: "Show entitlements",
|
|
392
|
+
type: "boolean",
|
|
393
|
+
defaultValue: true,
|
|
394
|
+
description: "List what the plan includes. Display only \u2014 entitlement is enforced server-side (AUTH L10)."
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
key: "staleAfterMs",
|
|
398
|
+
label: "Stale after (ms)",
|
|
399
|
+
type: "number",
|
|
400
|
+
defaultValue: 6e4,
|
|
401
|
+
description: "How old a balance may be before it is labelled stale."
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
key: "maxLedger",
|
|
405
|
+
label: "Max ledger entries",
|
|
406
|
+
type: "number",
|
|
407
|
+
defaultValue: 500,
|
|
408
|
+
description: "Entries retained in memory."
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
key: "emptyHint",
|
|
412
|
+
label: "Empty hint",
|
|
413
|
+
type: "text",
|
|
414
|
+
description: "Shown when no account state has arrived.",
|
|
415
|
+
placeholder: "Waiting for account state\u2026"
|
|
416
|
+
}
|
|
417
|
+
],
|
|
418
|
+
capabilities: ["storage.local"],
|
|
419
|
+
sdk: "^1.1.0"
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// src/auth/account/types.ts
|
|
423
|
+
var STEP_UP_ACTIONS = /* @__PURE__ */ new Set([
|
|
424
|
+
"signOut",
|
|
425
|
+
"manageBilling",
|
|
426
|
+
"purchase"
|
|
427
|
+
]);
|
|
428
|
+
function isSignedIn(status) {
|
|
429
|
+
return status === "signedIn" || status === "refreshing" || status === "offline";
|
|
430
|
+
}
|
|
431
|
+
function requiresStepUp(kind) {
|
|
432
|
+
return STEP_UP_ACTIONS.has(kind);
|
|
433
|
+
}
|
|
434
|
+
function creditsAge(credits, now) {
|
|
435
|
+
if (!credits) return null;
|
|
436
|
+
return Math.max(0, now - credits.asOf);
|
|
437
|
+
}
|
|
438
|
+
function formatAmount(amount, unit = "") {
|
|
439
|
+
const sign = amount > 0 ? "+" : "";
|
|
440
|
+
const suffix = unit ? ` ${unit}` : "";
|
|
441
|
+
return `${sign}${amount.toLocaleString()}${suffix}`;
|
|
442
|
+
}
|
|
443
|
+
function formatAge(ms) {
|
|
444
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s ago`;
|
|
445
|
+
if (ms < 36e5) return `${Math.round(ms / 6e4)}m ago`;
|
|
446
|
+
if (ms < 864e5) return `${Math.round(ms / 36e5)}h ago`;
|
|
447
|
+
return `${Math.round(ms / 864e5)}d ago`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/auth/account/declaration.ts
|
|
451
|
+
var accountViewManifest = {
|
|
452
|
+
id: ACCOUNT_PANEL_ID,
|
|
453
|
+
version: "1.0.0",
|
|
454
|
+
title: "Account",
|
|
455
|
+
category: "account",
|
|
456
|
+
layout: { slot: "side" },
|
|
457
|
+
inputs: [{ id: "view", type: "object", label: "View state", description: "The AccountViewState the controller derives from the host ports." }],
|
|
458
|
+
outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, seatId?, collapsed? } \u2014 applied by the controller." }],
|
|
459
|
+
commands: []
|
|
460
|
+
};
|
|
461
|
+
var STATUS_LABEL = {
|
|
462
|
+
unknown: "Loading",
|
|
463
|
+
signedOut: "Signed out",
|
|
464
|
+
signedIn: "Signed in",
|
|
465
|
+
refreshing: "Refreshing",
|
|
466
|
+
expired: "Session expired",
|
|
467
|
+
offline: "Offline"
|
|
468
|
+
};
|
|
469
|
+
var STATUS_TONE = {
|
|
470
|
+
unknown: "neutral",
|
|
471
|
+
signedOut: "neutral",
|
|
472
|
+
signedIn: "success",
|
|
473
|
+
refreshing: "neutral",
|
|
474
|
+
expired: "warning",
|
|
475
|
+
offline: "warning"
|
|
476
|
+
};
|
|
477
|
+
function accountPanelView(state, options = {}) {
|
|
478
|
+
const showLedger = options.showLedger ?? true;
|
|
479
|
+
const showEntitlements = options.showEntitlements ?? true;
|
|
480
|
+
const { identity, plan, credits } = state;
|
|
481
|
+
const signedIn = state.status !== "unknown" && isSignedIn(state.status);
|
|
482
|
+
return {
|
|
483
|
+
loading: state.status === "unknown",
|
|
484
|
+
signedOut: state.status !== "unknown" && !isSignedIn(state.status),
|
|
485
|
+
signedIn,
|
|
486
|
+
loadingHint: options.emptyHint ?? "Waiting for account state\u2026",
|
|
487
|
+
statusLabel: STATUS_LABEL[state.status],
|
|
488
|
+
statusTone: STATUS_TONE[state.status],
|
|
489
|
+
signedOutHint: state.message ?? "Sign in to see your plan and credits.",
|
|
490
|
+
planLabel: plan?.label,
|
|
491
|
+
planTitle: plan ? `Plan: ${plan.label}` : void 0,
|
|
492
|
+
name: identity?.name ?? identity?.sub,
|
|
493
|
+
email: identity?.email,
|
|
494
|
+
message: state.message ?? void 0,
|
|
495
|
+
hasCredits: credits !== null,
|
|
496
|
+
creditsUnit: credits?.unit ?? "credits",
|
|
497
|
+
creditsBalance: credits ? credits.balance.toLocaleString() : "",
|
|
498
|
+
creditsSub: credits && state.creditsAgeMs !== null ? state.creditsStale ? `stale \u2014 as of ${formatAge(state.creditsAgeMs)}` : `as of ${formatAge(state.creditsAgeMs)}` : void 0,
|
|
499
|
+
creditsStale: state.creditsStale,
|
|
500
|
+
creditsTitle: "Pushed by the host, not fetched by this panel.",
|
|
501
|
+
hasIncluded: credits?.included !== void 0,
|
|
502
|
+
includedValue: credits?.included !== void 0 ? credits.included.toLocaleString() : "",
|
|
503
|
+
includedSub: credits?.used === void 0 ? void 0 : `${credits.used.toLocaleString()} used`,
|
|
504
|
+
showSeats: state.seats.length > 1,
|
|
505
|
+
seats: state.seats.map((s) => ({ id: s.id, label: s.label, active: !!s.active, inactive: !s.active })),
|
|
506
|
+
showEntitlements: showEntitlements && state.entitlements.length > 0,
|
|
507
|
+
entitlements: state.entitlements.map((e) => ({ id: e.id, label: e.label, detail: e.detail, tone: e.included ? "success" : "neutral", text: e.included ? "yes" : "no" })),
|
|
508
|
+
showLedger,
|
|
509
|
+
ledgerCollapsed: !state.ledgerExpanded,
|
|
510
|
+
ledgerCount: state.ledger.length > 0 ? String(state.ledger.length) : void 0,
|
|
511
|
+
hasLedger: state.ledger.length > 0,
|
|
512
|
+
ledgerEmpty: state.ledger.length === 0,
|
|
513
|
+
ledger: state.ledger.map((e) => ({ id: e.id, description: e.description, source: e.source, amount: formatAmount(e.amount) })),
|
|
514
|
+
ledgerHasMore: state.ledgerHasMore,
|
|
515
|
+
renews: plan?.renewsAt ? `renews ${new Date(plan.renewsAt).toLocaleDateString()}` : void 0,
|
|
516
|
+
offlineNote: state.status === "offline" ? "offline \u2014 showing last known" : void 0
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
var EMPTY = { status: "unknown", identity: null, plan: null, credits: null, entitlements: [], seats: [], message: null, ledger: [], ledgerHasMore: false, ledgerExpanded: false, creditsAgeMs: null, creditsStale: false };
|
|
520
|
+
var BEHAVIOURS2 = {
|
|
521
|
+
"auth/accountPanelView": (inputs, config) => accountPanelView(inputs.view ?? EMPTY, {
|
|
522
|
+
showLedger: typeof config.showLedger === "boolean" ? config.showLedger : void 0,
|
|
523
|
+
showEntitlements: typeof config.showEntitlements === "boolean" ? config.showEntitlements : void 0,
|
|
524
|
+
emptyHint: typeof config.emptyHint === "string" ? config.emptyHint : void 0
|
|
525
|
+
})
|
|
526
|
+
};
|
|
527
|
+
var ui = (kind) => ({ emit: "ui", value: { object: { kind: { value: kind } } } });
|
|
528
|
+
var text = (b) => ({ component: "text", props: { text: b } });
|
|
529
|
+
var badge = (b, when, props) => ({ component: "chrome/Badge", ...when ? { when } : {}, ...props ? { props } : {}, children: [text(b)] });
|
|
530
|
+
var ACCOUNT_DECLARATION = {
|
|
531
|
+
format: "xeno.block@1",
|
|
532
|
+
manifest: accountViewManifest,
|
|
533
|
+
behaviour: "auth/accountPanelView",
|
|
534
|
+
composition: {
|
|
535
|
+
component: "fragment",
|
|
536
|
+
children: [
|
|
537
|
+
{ component: "chrome/EmptyState", when: { input: "view.loading" }, props: { title: { value: "Account" }, hint: { input: "view.loadingHint" } } },
|
|
538
|
+
{
|
|
539
|
+
component: "chrome/EmptyState",
|
|
540
|
+
when: { input: "view.signedOut" },
|
|
541
|
+
props: {
|
|
542
|
+
title: { input: "view.statusLabel" },
|
|
543
|
+
hint: { input: "view.signedOutHint" },
|
|
544
|
+
action: { node: { component: "chrome/TextButton", props: { strong: { value: true } }, on: { onClick: ui("signIn") }, children: [text({ value: "Sign in" })] } }
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
component: "chrome/Column",
|
|
549
|
+
when: { input: "view.signedIn" },
|
|
550
|
+
children: [
|
|
551
|
+
{
|
|
552
|
+
component: "chrome/Toolbar",
|
|
553
|
+
props: {
|
|
554
|
+
left: { node: { component: "chrome/ToolbarGroup", children: [badge({ input: "view.statusLabel" }, void 0, { tone: { input: "view.statusTone" } }), badge({ input: "view.planLabel" }, { input: "view.planLabel" }, { title: { input: "view.planTitle" } })] } },
|
|
555
|
+
right: { node: { component: "chrome/ToolbarGroup", props: { end: { value: true } }, children: [{ component: "chrome/TextButton", on: { onClick: ui("refresh") }, children: [text({ value: "Refresh" })] }] } }
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
component: "chrome/ScrollArea",
|
|
560
|
+
children: [
|
|
561
|
+
{
|
|
562
|
+
component: "chrome/Stack",
|
|
563
|
+
children: [
|
|
564
|
+
{ component: "chrome/Text", props: { role: { value: "title" } }, children: [text({ input: "view.name" })] },
|
|
565
|
+
{ component: "chrome/Text", when: { input: "view.email" }, props: { role: { value: "meta" } }, children: [text({ input: "view.email" })] },
|
|
566
|
+
{ component: "chrome/Text", when: { input: "view.message" }, props: { role: { value: "meta" } }, children: [text({ input: "view.message" })] }
|
|
567
|
+
]
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
component: "chrome/Stack",
|
|
571
|
+
when: { input: "view.hasCredits" },
|
|
572
|
+
props: { direction: { value: "row" }, pad: { value: "inset" } },
|
|
573
|
+
children: [
|
|
574
|
+
{
|
|
575
|
+
component: "chrome/StatTile",
|
|
576
|
+
props: {
|
|
577
|
+
label: { input: "view.creditsUnit" },
|
|
578
|
+
value: { input: "view.creditsBalance" },
|
|
579
|
+
sub: { input: "view.creditsSub" },
|
|
580
|
+
icon: { node: badge({ value: "stale" }, { input: "view.creditsStale" }, { tone: { value: "warning" } }) },
|
|
581
|
+
title: { input: "view.creditsTitle" }
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
{ component: "chrome/StatTile", when: { input: "view.hasIncluded" }, props: { label: { value: "included" }, value: { input: "view.includedValue" }, sub: { input: "view.includedSub" } } }
|
|
585
|
+
]
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
component: "chrome/Section",
|
|
589
|
+
when: { input: "view.showSeats" },
|
|
590
|
+
props: { title: { value: "Seats" }, flush: { value: true } },
|
|
591
|
+
children: [
|
|
592
|
+
{
|
|
593
|
+
component: "chrome/RowList",
|
|
594
|
+
children: [
|
|
595
|
+
{
|
|
596
|
+
component: "chrome/Row",
|
|
597
|
+
each: { input: "view.seats", key: "id" },
|
|
598
|
+
props: {
|
|
599
|
+
noIcon: { value: true },
|
|
600
|
+
label: { item: "label" },
|
|
601
|
+
trailing: {
|
|
602
|
+
node: {
|
|
603
|
+
component: "fragment",
|
|
604
|
+
children: [
|
|
605
|
+
badge({ value: "active" }, { item: "active" }),
|
|
606
|
+
{ component: "chrome/TextButton", when: { item: "inactive" }, on: { onClick: { emit: "ui", value: { object: { kind: { value: "switchSeat" }, seatId: { item: "id" } } } } }, children: [text({ value: "Switch" })] }
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
]
|
|
613
|
+
}
|
|
614
|
+
]
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
component: "chrome/Section",
|
|
618
|
+
when: { input: "view.showEntitlements" },
|
|
619
|
+
props: { title: { value: "Included" }, flush: { value: true } },
|
|
620
|
+
children: [
|
|
621
|
+
{
|
|
622
|
+
component: "chrome/RowList",
|
|
623
|
+
children: [
|
|
624
|
+
{
|
|
625
|
+
component: "chrome/Row",
|
|
626
|
+
each: { input: "view.entitlements", key: "id" },
|
|
627
|
+
props: { noIcon: { value: true }, label: { item: "label" }, meta: { item: "detail" }, trailing: { node: badge({ item: "text" }, void 0, { tone: { item: "tone" } }) } }
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
]
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
component: "chrome/Section",
|
|
635
|
+
when: { input: "view.showLedger" },
|
|
636
|
+
props: { title: { value: "Recent activity" }, flush: { value: true }, collapsed: { input: "view.ledgerCollapsed" }, badge: { node: badge({ input: "view.ledgerCount" }, { input: "view.ledgerCount" }) } },
|
|
637
|
+
on: { onCollapsedChange: { emit: "ui", value: { object: { kind: { value: "ledgerCollapsed" }, collapsed: { arg: "" } } } } },
|
|
638
|
+
children: [
|
|
639
|
+
{ component: "chrome/EmptyState", when: { input: "view.ledgerEmpty" }, props: { title: { value: "No activity" }, hint: { value: "Credit spends and grants appear here." } } },
|
|
640
|
+
{
|
|
641
|
+
component: "chrome/RowList",
|
|
642
|
+
when: { input: "view.hasLedger" },
|
|
643
|
+
children: [
|
|
644
|
+
{
|
|
645
|
+
component: "chrome/Row",
|
|
646
|
+
each: { input: "view.ledger", key: "id" },
|
|
647
|
+
props: { noIcon: { value: true }, label: { item: "description" }, meta: { item: "source" }, trailing: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text({ item: "amount" })] } } }
|
|
648
|
+
}
|
|
649
|
+
]
|
|
650
|
+
},
|
|
651
|
+
{ component: "chrome/Stack", when: { input: "view.ledgerHasMore" }, props: { pad: { value: "inset" } }, children: [{ component: "chrome/Text", props: { role: { value: "caption" } }, children: [text({ value: "Older entries are not held by this panel." })] }] }
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
{ component: "chrome/Stack", props: { pad: { value: "inset" } }, children: [{ component: "chrome/Text", props: { role: { value: "caption" } }, children: [text({ value: "Billing and sign-out ask you to confirm who you are." })] }] },
|
|
657
|
+
{
|
|
658
|
+
component: "chrome/Toolbar",
|
|
659
|
+
props: {
|
|
660
|
+
divided: { value: false },
|
|
661
|
+
right: {
|
|
662
|
+
node: {
|
|
663
|
+
component: "chrome/ToolbarGroup",
|
|
664
|
+
props: { end: { value: true } },
|
|
665
|
+
children: [
|
|
666
|
+
{ component: "chrome/TextButton", on: { onClick: ui("manageBilling") }, children: [text({ value: "Billing\u2026" })] },
|
|
667
|
+
{ component: "chrome/TextButton", on: { onClick: ui("signOut") }, children: [text({ value: "Sign out\u2026" })] }
|
|
668
|
+
]
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
{ component: "chrome/StatusBar", props: { left: { input: "view.renews" }, right: { input: "view.offlineNote" } } }
|
|
674
|
+
]
|
|
675
|
+
}
|
|
676
|
+
]
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
321
680
|
// src/auth/gate/mount.ts
|
|
322
681
|
import { createElement as createElement2 } from "react";
|
|
323
682
|
import { createRoot as createRoot2 } from "react-dom/client";
|
|
@@ -355,34 +714,6 @@ import {
|
|
|
355
714
|
bindConfig as bindConfig2
|
|
356
715
|
} from "@xenosystem/block-sdk";
|
|
357
716
|
|
|
358
|
-
// src/auth/account/types.ts
|
|
359
|
-
var STEP_UP_ACTIONS = /* @__PURE__ */ new Set([
|
|
360
|
-
"signOut",
|
|
361
|
-
"manageBilling",
|
|
362
|
-
"purchase"
|
|
363
|
-
]);
|
|
364
|
-
function isSignedIn(status) {
|
|
365
|
-
return status === "signedIn" || status === "refreshing" || status === "offline";
|
|
366
|
-
}
|
|
367
|
-
function requiresStepUp(kind) {
|
|
368
|
-
return STEP_UP_ACTIONS.has(kind);
|
|
369
|
-
}
|
|
370
|
-
function creditsAge(credits, now) {
|
|
371
|
-
if (!credits) return null;
|
|
372
|
-
return Math.max(0, now - credits.asOf);
|
|
373
|
-
}
|
|
374
|
-
function formatAmount(amount, unit = "") {
|
|
375
|
-
const sign = amount > 0 ? "+" : "";
|
|
376
|
-
const suffix = unit ? ` ${unit}` : "";
|
|
377
|
-
return `${sign}${amount.toLocaleString()}${suffix}`;
|
|
378
|
-
}
|
|
379
|
-
function formatAge(ms) {
|
|
380
|
-
if (ms < 6e4) return `${Math.round(ms / 1e3)}s ago`;
|
|
381
|
-
if (ms < 36e5) return `${Math.round(ms / 6e4)}m ago`;
|
|
382
|
-
if (ms < 864e5) return `${Math.round(ms / 36e5)}h ago`;
|
|
383
|
-
return `${Math.round(ms / 864e5)}d ago`;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
717
|
// src/auth/account/controller.ts
|
|
387
718
|
var EMPTY_STATE = { status: "unknown" };
|
|
388
719
|
function ageBucket(ms) {
|
|
@@ -593,107 +924,6 @@ var AccountController = class {
|
|
|
593
924
|
}
|
|
594
925
|
};
|
|
595
926
|
|
|
596
|
-
// src/auth/account/manifest.ts
|
|
597
|
-
import { WELL_KNOWN_PORT_SCHEMAS } from "@xenosystem/block-sdk";
|
|
598
|
-
var ACCOUNT_PANEL_ID = "xeno.core.account";
|
|
599
|
-
var accountManifest = {
|
|
600
|
-
id: ACCOUNT_PANEL_ID,
|
|
601
|
-
version: "0.1.0",
|
|
602
|
-
title: "Account",
|
|
603
|
-
icon: "user-round",
|
|
604
|
-
description: "Identity, plan, credits, entitlements and ledger \u2014 all host-pushed, never fetched. Balances carry the moment they were true. Sensitive actions are emitted as step-up intents, never performed.",
|
|
605
|
-
defaultSlot: "inspector",
|
|
606
|
-
inputs: [
|
|
607
|
-
{
|
|
608
|
-
id: "account",
|
|
609
|
-
name: "Account",
|
|
610
|
-
type: "object",
|
|
611
|
-
schema: WELL_KNOWN_PORT_SCHEMAS.ACCOUNT,
|
|
612
|
-
description: "{status, identity?, plan?, credits?, entitlements?, seats?, message?}. The host is authoritative. Contains NO token \u2014 see AUTH L9.",
|
|
613
|
-
multiple: false
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
id: "ledger",
|
|
617
|
-
name: "Ledger",
|
|
618
|
-
type: "object",
|
|
619
|
-
schema: WELL_KNOWN_PORT_SCHEMAS.LEDGER,
|
|
620
|
-
description: "{rev?, append?, replace?, clear?, hasMore?}. Append-oriented; `rev` gates out-of-order deliveries.",
|
|
621
|
-
multiple: true
|
|
622
|
-
}
|
|
623
|
-
],
|
|
624
|
-
outputs: [
|
|
625
|
-
{
|
|
626
|
-
id: "action",
|
|
627
|
-
name: "Action",
|
|
628
|
-
type: "object",
|
|
629
|
-
schema: WELL_KNOWN_PORT_SCHEMAS.ACCOUNT_ACTION,
|
|
630
|
-
description: "{kind, seatId?, productId?, stepUp?}. An INTENT. `stepUp: true` marks an action AUTH L12 requires a fresh interactive re-auth for; the host must not satisfy it silently from the broker."
|
|
631
|
-
}
|
|
632
|
-
],
|
|
633
|
-
commands: [
|
|
634
|
-
{
|
|
635
|
-
id: "refresh",
|
|
636
|
-
title: "Refresh",
|
|
637
|
-
description: "Ask the host to re-read the balance. Idempotent; no step-up.",
|
|
638
|
-
parameters: {}
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
id: "get_account",
|
|
642
|
-
title: "Get Account",
|
|
643
|
-
description: "Return the rendered account state \u2014 status, plan, balance and its asOf. Never a token.",
|
|
644
|
-
parameters: {}
|
|
645
|
-
},
|
|
646
|
-
{
|
|
647
|
-
id: "get_ledger",
|
|
648
|
-
title: "Get Ledger",
|
|
649
|
-
description: "Return the held ledger entries, newest first.",
|
|
650
|
-
parameters: {}
|
|
651
|
-
}
|
|
652
|
-
// NOTE: `signOut`, `purchase` and `manageBilling` are deliberately NOT commands. They require a
|
|
653
|
-
// fresh interactive re-auth (AUTH L12), and an agent-invocable command is by definition not
|
|
654
|
-
// interactive. Exposing them would make this panel the bypass for the step-up requirement.
|
|
655
|
-
],
|
|
656
|
-
config: [
|
|
657
|
-
{
|
|
658
|
-
key: "showLedger",
|
|
659
|
-
label: "Show ledger",
|
|
660
|
-
type: "boolean",
|
|
661
|
-
defaultValue: true,
|
|
662
|
-
description: "Show recent credit activity."
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
key: "showEntitlements",
|
|
666
|
-
label: "Show entitlements",
|
|
667
|
-
type: "boolean",
|
|
668
|
-
defaultValue: true,
|
|
669
|
-
description: "List what the plan includes. Display only \u2014 entitlement is enforced server-side (AUTH L10)."
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
key: "staleAfterMs",
|
|
673
|
-
label: "Stale after (ms)",
|
|
674
|
-
type: "number",
|
|
675
|
-
defaultValue: 6e4,
|
|
676
|
-
description: "How old a balance may be before it is labelled stale."
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
key: "maxLedger",
|
|
680
|
-
label: "Max ledger entries",
|
|
681
|
-
type: "number",
|
|
682
|
-
defaultValue: 500,
|
|
683
|
-
description: "Entries retained in memory."
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
key: "emptyHint",
|
|
687
|
-
label: "Empty hint",
|
|
688
|
-
type: "text",
|
|
689
|
-
description: "Shown when no account state has arrived.",
|
|
690
|
-
placeholder: "Waiting for account state\u2026"
|
|
691
|
-
}
|
|
692
|
-
],
|
|
693
|
-
capabilities: ["storage.local"],
|
|
694
|
-
sdk: "^1.1.0"
|
|
695
|
-
};
|
|
696
|
-
|
|
697
927
|
// src/auth/account/react/AccountPanelView.tsx
|
|
698
928
|
import { useSyncExternalStore } from "react";
|
|
699
929
|
import {
|
|
@@ -712,23 +942,7 @@ import {
|
|
|
712
942
|
Toolbar,
|
|
713
943
|
ToolbarGroup
|
|
714
944
|
} from "@xenosystem/components/chrome";
|
|
715
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
716
|
-
var STATUS_LABEL = {
|
|
717
|
-
unknown: "Loading",
|
|
718
|
-
signedOut: "Signed out",
|
|
719
|
-
signedIn: "Signed in",
|
|
720
|
-
refreshing: "Refreshing",
|
|
721
|
-
expired: "Session expired",
|
|
722
|
-
offline: "Offline"
|
|
723
|
-
};
|
|
724
|
-
var STATUS_TONE = {
|
|
725
|
-
unknown: "neutral",
|
|
726
|
-
signedOut: "neutral",
|
|
727
|
-
signedIn: "success",
|
|
728
|
-
refreshing: "neutral",
|
|
729
|
-
expired: "warning",
|
|
730
|
-
offline: "warning"
|
|
731
|
-
};
|
|
945
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
732
946
|
function AccountPanelView({
|
|
733
947
|
controller,
|
|
734
948
|
showLedger = true,
|
|
@@ -736,103 +950,76 @@ function AccountPanelView({
|
|
|
736
950
|
emptyHint
|
|
737
951
|
}) {
|
|
738
952
|
const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
if (!isSignedIn(state.status)) {
|
|
953
|
+
const v = accountPanelView(state, { showLedger, showEntitlements, emptyHint });
|
|
954
|
+
if (v.loading) return /* @__PURE__ */ jsx2(EmptyState, { title: "Account", hint: v.loadingHint });
|
|
955
|
+
if (v.signedOut) {
|
|
743
956
|
return /* @__PURE__ */ jsx2(
|
|
744
957
|
EmptyState,
|
|
745
958
|
{
|
|
746
|
-
title:
|
|
747
|
-
hint:
|
|
959
|
+
title: v.statusLabel,
|
|
960
|
+
hint: v.signedOutHint,
|
|
748
961
|
action: /* @__PURE__ */ jsx2(TextButton, { strong: true, onClick: () => controller.request("signIn"), children: "Sign in" })
|
|
749
962
|
}
|
|
750
963
|
);
|
|
751
964
|
}
|
|
752
|
-
const { identity, plan, credits } = state;
|
|
753
|
-
const unit = credits?.unit ?? "credits";
|
|
754
965
|
return /* @__PURE__ */ jsxs(Column, { children: [
|
|
755
966
|
/* @__PURE__ */ jsx2(
|
|
756
967
|
Toolbar,
|
|
757
968
|
{
|
|
758
969
|
left: /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
|
|
759
|
-
/* @__PURE__ */ jsx2(Badge, { tone:
|
|
760
|
-
|
|
970
|
+
/* @__PURE__ */ jsx2(Badge, { tone: v.statusTone, children: v.statusLabel }),
|
|
971
|
+
v.planLabel ? /* @__PURE__ */ jsx2(Badge, { title: v.planTitle, children: v.planLabel }) : null
|
|
761
972
|
] }),
|
|
762
973
|
right: /* @__PURE__ */ jsx2(ToolbarGroup, { end: true, children: /* @__PURE__ */ jsx2(TextButton, { onClick: () => controller.refresh(), children: "Refresh" }) })
|
|
763
974
|
}
|
|
764
975
|
),
|
|
765
976
|
/* @__PURE__ */ jsxs(ScrollArea, { children: [
|
|
766
977
|
/* @__PURE__ */ jsxs(Stack, { children: [
|
|
767
|
-
/* @__PURE__ */ jsx2(Text, { role: "title", children:
|
|
768
|
-
|
|
769
|
-
|
|
978
|
+
/* @__PURE__ */ jsx2(Text, { role: "title", children: v.name }),
|
|
979
|
+
v.email ? /* @__PURE__ */ jsx2(Text, { role: "meta", children: v.email }) : null,
|
|
980
|
+
v.message ? /* @__PURE__ */ jsx2(Text, { role: "meta", children: v.message }) : null
|
|
770
981
|
] }),
|
|
771
|
-
|
|
982
|
+
v.hasCredits ? /* @__PURE__ */ jsxs(Stack, { direction: "row", pad: "inset", children: [
|
|
772
983
|
/* @__PURE__ */ jsx2(
|
|
773
984
|
StatTile,
|
|
774
985
|
{
|
|
775
|
-
label:
|
|
776
|
-
value:
|
|
777
|
-
sub:
|
|
778
|
-
icon:
|
|
779
|
-
title:
|
|
986
|
+
label: v.creditsUnit,
|
|
987
|
+
value: v.creditsBalance,
|
|
988
|
+
sub: v.creditsSub,
|
|
989
|
+
icon: v.creditsStale ? /* @__PURE__ */ jsx2(Badge, { tone: "warning", children: "stale" }) : null,
|
|
990
|
+
title: v.creditsTitle
|
|
780
991
|
}
|
|
781
992
|
),
|
|
782
|
-
|
|
783
|
-
StatTile,
|
|
784
|
-
{
|
|
785
|
-
label: "included",
|
|
786
|
-
value: credits.included.toLocaleString(),
|
|
787
|
-
sub: credits.used === void 0 ? void 0 : `${credits.used.toLocaleString()} used`
|
|
788
|
-
}
|
|
789
|
-
) : null
|
|
993
|
+
v.hasIncluded ? /* @__PURE__ */ jsx2(StatTile, { label: "included", value: v.includedValue, sub: v.includedSub }) : null
|
|
790
994
|
] }) : null,
|
|
791
|
-
|
|
995
|
+
v.showSeats ? /* @__PURE__ */ jsx2(Section, { title: "Seats", flush: true, children: /* @__PURE__ */ jsx2(RowList, { children: v.seats.map((seat) => /* @__PURE__ */ jsx2(
|
|
792
996
|
Row,
|
|
793
997
|
{
|
|
794
998
|
noIcon: true,
|
|
795
999
|
label: seat.label,
|
|
796
|
-
trailing:
|
|
797
|
-
|
|
798
|
-
{
|
|
799
|
-
|
|
800
|
-
children: "Switch"
|
|
801
|
-
}
|
|
802
|
-
)
|
|
1000
|
+
trailing: /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1001
|
+
seat.active ? /* @__PURE__ */ jsx2(Badge, { children: "active" }) : null,
|
|
1002
|
+
seat.inactive ? /* @__PURE__ */ jsx2(TextButton, { onClick: () => controller.request("switchSeat", { seatId: seat.id }), children: "Switch" }) : null
|
|
1003
|
+
] })
|
|
803
1004
|
},
|
|
804
1005
|
seat.id
|
|
805
1006
|
)) }) }) : null,
|
|
806
|
-
showEntitlements
|
|
807
|
-
|
|
808
|
-
{
|
|
809
|
-
noIcon: true,
|
|
810
|
-
label: ent.label,
|
|
811
|
-
meta: ent.detail,
|
|
812
|
-
trailing: /* @__PURE__ */ jsx2(Badge, { tone: ent.included ? "success" : "neutral", children: ent.included ? "yes" : "no" })
|
|
813
|
-
},
|
|
814
|
-
ent.id
|
|
1007
|
+
v.showEntitlements ? /* @__PURE__ */ jsx2(Section, { title: "Included", flush: true, children: /* @__PURE__ */ jsx2(RowList, { children: v.entitlements.map((ent) => (
|
|
1008
|
+
// A fact about the plan, not a permission check. The gate is server-side (L10).
|
|
1009
|
+
/* @__PURE__ */ jsx2(Row, { noIcon: true, label: ent.label, meta: ent.detail, trailing: /* @__PURE__ */ jsx2(Badge, { tone: ent.tone, children: ent.text }) }, ent.id)
|
|
815
1010
|
)) }) }) : null,
|
|
816
|
-
showLedger ? /* @__PURE__ */ jsxs(
|
|
1011
|
+
v.showLedger ? /* @__PURE__ */ jsxs(
|
|
817
1012
|
Section,
|
|
818
1013
|
{
|
|
819
1014
|
title: "Recent activity",
|
|
820
1015
|
flush: true,
|
|
821
|
-
collapsed:
|
|
1016
|
+
collapsed: v.ledgerCollapsed,
|
|
822
1017
|
onCollapsedChange: (collapsed) => controller.setLedgerExpanded(!collapsed),
|
|
823
|
-
badge:
|
|
1018
|
+
badge: v.ledgerCount ? /* @__PURE__ */ jsx2(Badge, { children: v.ledgerCount }) : null,
|
|
824
1019
|
children: [
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
noIcon: true,
|
|
829
|
-
label: entry.description,
|
|
830
|
-
meta: entry.source,
|
|
831
|
-
trailing: /* @__PURE__ */ jsx2(Text, { role: "number", children: formatAmount(entry.amount) })
|
|
832
|
-
},
|
|
833
|
-
entry.id
|
|
834
|
-
)) }),
|
|
835
|
-
state.ledgerHasMore ? /* @__PURE__ */ jsx2(Stack, { pad: "inset", children: /* @__PURE__ */ jsx2(Text, { role: "caption", children: "Older entries are not held by this panel." }) }) : null
|
|
1020
|
+
v.ledgerEmpty ? /* @__PURE__ */ jsx2(EmptyState, { title: "No activity", hint: "Credit spends and grants appear here." }) : null,
|
|
1021
|
+
v.hasLedger ? /* @__PURE__ */ jsx2(RowList, { children: v.ledger.map((entry) => /* @__PURE__ */ jsx2(Row, { noIcon: true, label: entry.description, meta: entry.source, trailing: /* @__PURE__ */ jsx2(Text, { role: "number", children: entry.amount }) }, entry.id)) }) : null,
|
|
1022
|
+
v.ledgerHasMore ? /* @__PURE__ */ jsx2(Stack, { pad: "inset", children: /* @__PURE__ */ jsx2(Text, { role: "caption", children: "Older entries are not held by this panel." }) }) : null
|
|
836
1023
|
]
|
|
837
1024
|
}
|
|
838
1025
|
) : null
|
|
@@ -848,13 +1035,7 @@ function AccountPanelView({
|
|
|
848
1035
|
] })
|
|
849
1036
|
}
|
|
850
1037
|
),
|
|
851
|
-
/* @__PURE__ */ jsx2(
|
|
852
|
-
StatusBar,
|
|
853
|
-
{
|
|
854
|
-
left: plan?.renewsAt ? `renews ${new Date(plan.renewsAt).toLocaleDateString()}` : void 0,
|
|
855
|
-
right: state.status === "offline" ? "offline \u2014 showing last known" : void 0
|
|
856
|
-
}
|
|
857
|
-
)
|
|
1038
|
+
/* @__PURE__ */ jsx2(StatusBar, { left: v.renews, right: v.offlineNote })
|
|
858
1039
|
] });
|
|
859
1040
|
}
|
|
860
1041
|
|
|
@@ -958,7 +1139,12 @@ function createAccountPanel(options = {}) {
|
|
|
958
1139
|
};
|
|
959
1140
|
}
|
|
960
1141
|
var accountPanel = createAccountPanel();
|
|
1142
|
+
|
|
1143
|
+
// src/auth/index.ts
|
|
1144
|
+
var BEHAVIOURS3 = { ...BEHAVIOURS, ...BEHAVIOURS2 };
|
|
961
1145
|
export {
|
|
1146
|
+
BEHAVIOURS2 as ACCOUNT_BEHAVIOURS,
|
|
1147
|
+
ACCOUNT_DECLARATION,
|
|
962
1148
|
ACCOUNT_PANEL_ID,
|
|
963
1149
|
AUTH_GATE_DECLARATION,
|
|
964
1150
|
AUTH_GATE_INITIAL,
|
|
@@ -967,11 +1153,15 @@ export {
|
|
|
967
1153
|
AccountPanelView,
|
|
968
1154
|
AuthGateController,
|
|
969
1155
|
AuthGateView,
|
|
970
|
-
BEHAVIOURS,
|
|
1156
|
+
BEHAVIOURS3 as BEHAVIOURS,
|
|
971
1157
|
PHASE_INTENTS,
|
|
1158
|
+
STATUS_LABEL,
|
|
1159
|
+
STATUS_TONE,
|
|
972
1160
|
STEP_UP_ACTIONS,
|
|
973
1161
|
accountManifest,
|
|
974
1162
|
accountPanel,
|
|
1163
|
+
accountPanelView,
|
|
1164
|
+
accountViewManifest,
|
|
975
1165
|
authGateManifest,
|
|
976
1166
|
authGatePanel,
|
|
977
1167
|
authGateView,
|
package/dist/time/index.js
CHANGED
|
@@ -780,6 +780,7 @@ function ticksPerStep(unit, timebase) {
|
|
|
780
780
|
|
|
781
781
|
// src/time/transport/react/TransportPanelView.tsx
|
|
782
782
|
import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
|
|
783
|
+
import { Column, IconButton, NumberInput, Readout, Slider, Stack, TextButton } from "@xenosystem/components/chrome";
|
|
783
784
|
|
|
784
785
|
// src/time/transport/react/icons.tsx
|
|
785
786
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -928,9 +929,8 @@ function TransportPanelView({ controller }) {
|
|
|
928
929
|
[controller]
|
|
929
930
|
);
|
|
930
931
|
return /* @__PURE__ */ jsxs2(
|
|
931
|
-
|
|
932
|
+
Column,
|
|
932
933
|
{
|
|
933
|
-
style: S.root,
|
|
934
934
|
className: "xeno-transport-panel",
|
|
935
935
|
onKeyDown,
|
|
936
936
|
onKeyUp,
|
|
@@ -938,228 +938,66 @@ function TransportPanelView({ controller }) {
|
|
|
938
938
|
role: "group",
|
|
939
939
|
"aria-label": "Transport",
|
|
940
940
|
children: [
|
|
941
|
-
/* @__PURE__ */ jsxs2(
|
|
942
|
-
/* @__PURE__ */ jsx2(
|
|
943
|
-
/* @__PURE__ */ jsx2(
|
|
944
|
-
controller.showsControl("shuttle") && /* @__PURE__ */ jsx2(
|
|
941
|
+
/* @__PURE__ */ jsxs2(Stack, { direction: "row", gap: 3, pad: "gutter", children: [
|
|
942
|
+
/* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(StartIcon, {}), label: "Go to start", onClick: () => controller.goToStart() }),
|
|
943
|
+
/* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(StepBackIcon, {}), label: "Step back", onClick: () => controller.step(-1) }),
|
|
944
|
+
controller.showsControl("shuttle") && /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(ShuttleLeftIcon, {}), label: "Shuttle reverse (J)", onClick: () => controller.shuttleStep(-1) }),
|
|
945
945
|
/* @__PURE__ */ jsx2(
|
|
946
|
-
|
|
947
|
-
{
|
|
948
|
-
type: "button",
|
|
949
|
-
style: { ...S.iconBtn, ...S.primaryBtn },
|
|
950
|
-
onClick: () => controller.togglePlay(),
|
|
951
|
-
title: playing ? "Pause (Space)" : "Play (Space)",
|
|
952
|
-
"aria-label": playing ? "Pause" : "Play",
|
|
953
|
-
"aria-pressed": playing,
|
|
954
|
-
children: playing ? /* @__PURE__ */ jsx2(PauseIcon, {}) : /* @__PURE__ */ jsx2(PlayIcon, {})
|
|
955
|
-
}
|
|
956
|
-
),
|
|
957
|
-
/* @__PURE__ */ jsx2("button", { type: "button", style: S.iconBtn, onClick: () => controller.stop(), title: "Stop", "aria-label": "Stop", children: /* @__PURE__ */ jsx2(StopIcon, {}) }),
|
|
958
|
-
controller.showsControl("shuttle") && /* @__PURE__ */ jsx2("button", { type: "button", style: S.iconBtn, onClick: () => controller.shuttleStep(1), title: "Shuttle forward (L)", "aria-label": "Shuttle forward", children: /* @__PURE__ */ jsx2(ShuttleRightIcon, {}) }),
|
|
959
|
-
/* @__PURE__ */ jsx2("button", { type: "button", style: S.iconBtn, onClick: () => controller.step(1), title: "Step forward", "aria-label": "Step forward", children: /* @__PURE__ */ jsx2(StepForwardIcon, {}) }),
|
|
960
|
-
/* @__PURE__ */ jsx2("button", { type: "button", style: S.iconBtn, onClick: () => controller.goToEnd(), title: "Go to end", "aria-label": "Go to end", children: /* @__PURE__ */ jsx2(EndIcon, {}) }),
|
|
961
|
-
controller.showsControl("record") && /* @__PURE__ */ jsx2(
|
|
962
|
-
"button",
|
|
946
|
+
IconButton,
|
|
963
947
|
{
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
children: /* @__PURE__ */ jsx2(RecordIcon, {})
|
|
948
|
+
size: "sm",
|
|
949
|
+
variant: "primary",
|
|
950
|
+
icon: playing ? /* @__PURE__ */ jsx2(PauseIcon, {}) : /* @__PURE__ */ jsx2(PlayIcon, {}),
|
|
951
|
+
label: playing ? "Pause (Space)" : "Play (Space)",
|
|
952
|
+
active: playing,
|
|
953
|
+
onClick: () => controller.togglePlay()
|
|
971
954
|
}
|
|
972
955
|
),
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
984
|
-
),
|
|
985
|
-
controller.showsControl("metronome") && /* @__PURE__ */ jsx2(
|
|
986
|
-
"button",
|
|
987
|
-
{
|
|
988
|
-
type: "button",
|
|
989
|
-
style: { ...S.iconBtn, opacity: state.metronome ? 1 : 0.4 },
|
|
990
|
-
onClick: () => controller.toggleMetronome(),
|
|
991
|
-
title: "Metronome",
|
|
992
|
-
"aria-label": "Metronome",
|
|
993
|
-
"aria-pressed": !!state.metronome,
|
|
994
|
-
children: /* @__PURE__ */ jsx2(MetronomeIcon, {})
|
|
995
|
-
}
|
|
996
|
-
),
|
|
997
|
-
controller.showsControl("punch") && /* @__PURE__ */ jsx2("button", { type: "button", style: { ...S.chipBtn, opacity: state.punch ? 1 : 0.4 }, "aria-pressed": !!state.punch, title: "Punch", children: "PUNCH" }),
|
|
998
|
-
/* @__PURE__ */ jsxs2(
|
|
999
|
-
"button",
|
|
956
|
+
/* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(StopIcon, {}), label: "Stop", onClick: () => controller.stop() }),
|
|
957
|
+
controller.showsControl("shuttle") && /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(ShuttleRightIcon, {}), label: "Shuttle forward (L)", onClick: () => controller.shuttleStep(1) }),
|
|
958
|
+
/* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(StepForwardIcon, {}), label: "Step forward", onClick: () => controller.step(1) }),
|
|
959
|
+
/* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(EndIcon, {}), label: "Go to end", onClick: () => controller.goToEnd() }),
|
|
960
|
+
controller.showsControl("record") && /* @__PURE__ */ jsx2(IconButton, { size: "sm", variant: "danger", icon: /* @__PURE__ */ jsx2(RecordIcon, {}), label: "Record", active: !!state.recording, onClick: () => controller.record() }),
|
|
961
|
+
controller.showsControl("loop") && /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(LoopIcon, {}), label: "Loop", active: !!state.loopEnabled, onClick: () => controller.toggleLoop() }),
|
|
962
|
+
controller.showsControl("metronome") && /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(MetronomeIcon, {}), label: "Metronome", active: !!state.metronome, onClick: () => controller.toggleMetronome() }),
|
|
963
|
+
controller.showsControl("punch") && /* @__PURE__ */ jsx2(TextButton, { strong: !!state.punch, children: "PUNCH" }),
|
|
964
|
+
/* @__PURE__ */ jsx2(
|
|
965
|
+
Readout,
|
|
1000
966
|
{
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
967
|
+
value: controller.getReadout(),
|
|
968
|
+
unit: (0, format_exports.displayLabel)(controller.getDisplay()),
|
|
969
|
+
label: `Position ${controller.getReadout()}`,
|
|
1004
970
|
title: "Click to change time display",
|
|
1005
|
-
|
|
1006
|
-
children: [
|
|
1007
|
-
/* @__PURE__ */ jsx2("span", { style: S.readoutValue, children: controller.getReadout() }),
|
|
1008
|
-
/* @__PURE__ */ jsx2("span", { style: S.readoutUnit, children: (0, format_exports.displayLabel)(controller.getDisplay()) })
|
|
1009
|
-
]
|
|
971
|
+
onClick: () => controller.cycleDisplay()
|
|
1010
972
|
}
|
|
1011
973
|
),
|
|
1012
|
-
/* @__PURE__ */ jsx2(
|
|
1013
|
-
controller.showsControl("bpm") && /* @__PURE__ */
|
|
1014
|
-
|
|
1015
|
-
/* @__PURE__ */ jsx2(
|
|
1016
|
-
|
|
1017
|
-
{
|
|
1018
|
-
type: "number",
|
|
1019
|
-
value: state.bpm ?? 120,
|
|
1020
|
-
onChange: (e) => controller.setTempo(Number(e.target.value)),
|
|
1021
|
-
style: S.bpmInput,
|
|
1022
|
-
"aria-label": "Tempo"
|
|
1023
|
-
}
|
|
1024
|
-
)
|
|
1025
|
-
] }),
|
|
1026
|
-
controller.showsControl("inOut") && /* @__PURE__ */ jsxs2("span", { style: S.inOut, children: [
|
|
1027
|
-
/* @__PURE__ */ jsx2("button", { type: "button", style: S.chipBtn, onClick: () => controller.setInPoint(), title: "Set in point", children: "IN" }),
|
|
1028
|
-
/* @__PURE__ */ jsx2("button", { type: "button", style: S.chipBtn, onClick: () => controller.setOutPoint(), title: "Set out point", children: "OUT" })
|
|
974
|
+
/* @__PURE__ */ jsx2(Readout, { size: "sm", value: controller.getDurationReadout() }),
|
|
975
|
+
controller.showsControl("bpm") && /* @__PURE__ */ jsx2(NumberInput, { caption: "BPM", label: "Tempo", value: state.bpm ?? 120, onChange: (bpm) => controller.setTempo(bpm) }),
|
|
976
|
+
controller.showsControl("inOut") && /* @__PURE__ */ jsxs2(Stack, { direction: "row", gap: 2, pad: "none", children: [
|
|
977
|
+
/* @__PURE__ */ jsx2(TextButton, { onClick: () => controller.setInPoint(), children: "IN" }),
|
|
978
|
+
/* @__PURE__ */ jsx2(TextButton, { onClick: () => controller.setOutPoint(), children: "OUT" })
|
|
1029
979
|
] })
|
|
1030
980
|
] }),
|
|
1031
|
-
controller.showsControl("scrubber") && /* @__PURE__ */
|
|
1032
|
-
|
|
981
|
+
controller.showsControl("scrubber") && /* @__PURE__ */ jsx2(
|
|
982
|
+
Slider,
|
|
1033
983
|
{
|
|
1034
|
-
|
|
1035
|
-
|
|
984
|
+
trackRef: scrubRef,
|
|
985
|
+
progress: controller.getProgress(),
|
|
986
|
+
label: "Playhead",
|
|
987
|
+
valueMin: 0,
|
|
988
|
+
valueMax: controller.getDuration(),
|
|
989
|
+
valueNow: controller.getCurrentTick(),
|
|
990
|
+
valueText: controller.getReadout(),
|
|
1036
991
|
onPointerDown: onScrubDown,
|
|
1037
992
|
onPointerMove: onScrubMove,
|
|
1038
993
|
onPointerUp: onScrubUp,
|
|
1039
|
-
onPointerCancel: () => controller.cancelScrub()
|
|
1040
|
-
role: "slider",
|
|
1041
|
-
"aria-label": "Playhead",
|
|
1042
|
-
"aria-valuemin": 0,
|
|
1043
|
-
"aria-valuemax": controller.getDuration(),
|
|
1044
|
-
"aria-valuenow": controller.getCurrentTick(),
|
|
1045
|
-
"aria-valuetext": controller.getReadout(),
|
|
1046
|
-
tabIndex: 0,
|
|
1047
|
-
children: [
|
|
1048
|
-
/* @__PURE__ */ jsx2("span", { style: { ...S.scrubFill, width: `${controller.getProgress() * 100}%` } }),
|
|
1049
|
-
/* @__PURE__ */ jsx2("span", { style: { ...S.scrubKnob, left: `${controller.getProgress() * 100}%` } })
|
|
1050
|
-
]
|
|
994
|
+
onPointerCancel: () => controller.cancelScrub()
|
|
1051
995
|
}
|
|
1052
996
|
)
|
|
1053
997
|
]
|
|
1054
998
|
}
|
|
1055
999
|
);
|
|
1056
1000
|
}
|
|
1057
|
-
var S = {
|
|
1058
|
-
root: {
|
|
1059
|
-
display: "flex",
|
|
1060
|
-
flexDirection: "column",
|
|
1061
|
-
gap: 3,
|
|
1062
|
-
padding: "4px 6px",
|
|
1063
|
-
fontSize: 11,
|
|
1064
|
-
color: "var(--xeno-text)",
|
|
1065
|
-
background: "var(--xeno-canvas)",
|
|
1066
|
-
userSelect: "none",
|
|
1067
|
-
outline: "none"
|
|
1068
|
-
},
|
|
1069
|
-
row: { display: "flex", alignItems: "center", gap: 3, flexWrap: "wrap" },
|
|
1070
|
-
iconBtn: {
|
|
1071
|
-
display: "flex",
|
|
1072
|
-
alignItems: "center",
|
|
1073
|
-
justifyContent: "center",
|
|
1074
|
-
width: 20,
|
|
1075
|
-
height: 18,
|
|
1076
|
-
padding: 0,
|
|
1077
|
-
border: "none",
|
|
1078
|
-
borderRadius: 2,
|
|
1079
|
-
background: "var(--xeno-border-subtle)",
|
|
1080
|
-
color: "inherit",
|
|
1081
|
-
cursor: "pointer",
|
|
1082
|
-
flex: "0 0 auto"
|
|
1083
|
-
},
|
|
1084
|
-
primaryBtn: { background: "var(--xeno-control)", width: 26 },
|
|
1085
|
-
chipBtn: {
|
|
1086
|
-
height: 18,
|
|
1087
|
-
padding: "0 5px",
|
|
1088
|
-
border: "none",
|
|
1089
|
-
borderRadius: 2,
|
|
1090
|
-
background: "var(--xeno-border-subtle)",
|
|
1091
|
-
color: "inherit",
|
|
1092
|
-
cursor: "pointer",
|
|
1093
|
-
fontSize: 9,
|
|
1094
|
-
letterSpacing: "0.05em",
|
|
1095
|
-
flex: "0 0 auto"
|
|
1096
|
-
},
|
|
1097
|
-
readout: {
|
|
1098
|
-
display: "flex",
|
|
1099
|
-
alignItems: "baseline",
|
|
1100
|
-
gap: 4,
|
|
1101
|
-
height: 18,
|
|
1102
|
-
padding: "0 6px",
|
|
1103
|
-
marginLeft: 4,
|
|
1104
|
-
border: "1px solid var(--xeno-border)",
|
|
1105
|
-
borderRadius: 2,
|
|
1106
|
-
background: "var(--xeno-canvas)",
|
|
1107
|
-
color: "inherit",
|
|
1108
|
-
cursor: "pointer",
|
|
1109
|
-
flex: "0 0 auto"
|
|
1110
|
-
},
|
|
1111
|
-
readoutValue: { fontVariantNumeric: "tabular-nums", fontSize: 12, letterSpacing: "0.02em" },
|
|
1112
|
-
readoutUnit: { fontSize: 8, color: "var(--xeno-muted)", letterSpacing: "0.06em" },
|
|
1113
|
-
duration: {
|
|
1114
|
-
fontVariantNumeric: "tabular-nums",
|
|
1115
|
-
fontSize: 10,
|
|
1116
|
-
color: "var(--xeno-muted)",
|
|
1117
|
-
flex: "0 0 auto"
|
|
1118
|
-
},
|
|
1119
|
-
bpm: { display: "flex", alignItems: "center", gap: 3, flex: "0 0 auto" },
|
|
1120
|
-
bpmLabel: { fontSize: 8, color: "var(--xeno-muted)", letterSpacing: "0.06em" },
|
|
1121
|
-
bpmInput: {
|
|
1122
|
-
width: 42,
|
|
1123
|
-
height: 18,
|
|
1124
|
-
background: "var(--xeno-canvas)",
|
|
1125
|
-
color: "inherit",
|
|
1126
|
-
border: "1px solid var(--xeno-border)",
|
|
1127
|
-
borderRadius: 2,
|
|
1128
|
-
fontSize: 11,
|
|
1129
|
-
padding: "0 4px",
|
|
1130
|
-
outline: "none",
|
|
1131
|
-
fontVariantNumeric: "tabular-nums"
|
|
1132
|
-
},
|
|
1133
|
-
inOut: { display: "flex", gap: 2, flex: "0 0 auto" },
|
|
1134
|
-
scrubTrack: {
|
|
1135
|
-
position: "relative",
|
|
1136
|
-
height: 8,
|
|
1137
|
-
borderRadius: 2,
|
|
1138
|
-
background: "var(--xeno-border-subtle)",
|
|
1139
|
-
cursor: "pointer",
|
|
1140
|
-
touchAction: "none",
|
|
1141
|
-
outline: "none"
|
|
1142
|
-
},
|
|
1143
|
-
scrubFill: {
|
|
1144
|
-
position: "absolute",
|
|
1145
|
-
left: 0,
|
|
1146
|
-
top: 0,
|
|
1147
|
-
bottom: 0,
|
|
1148
|
-
background: "var(--xeno-control)",
|
|
1149
|
-
borderRadius: 2,
|
|
1150
|
-
pointerEvents: "none"
|
|
1151
|
-
},
|
|
1152
|
-
scrubKnob: {
|
|
1153
|
-
position: "absolute",
|
|
1154
|
-
top: -1,
|
|
1155
|
-
width: 3,
|
|
1156
|
-
height: 10,
|
|
1157
|
-
marginLeft: -1,
|
|
1158
|
-
background: "var(--xeno-text)",
|
|
1159
|
-
borderRadius: 1,
|
|
1160
|
-
pointerEvents: "none"
|
|
1161
|
-
}
|
|
1162
|
-
};
|
|
1163
1001
|
|
|
1164
1002
|
// src/time/transport/panel.ts
|
|
1165
1003
|
function createTransportPanel(options = {}) {
|
|
@@ -4177,13 +4015,13 @@ import {
|
|
|
4177
4015
|
Badge,
|
|
4178
4016
|
EmptyState as EmptyState2,
|
|
4179
4017
|
ErrorState,
|
|
4180
|
-
IconButton,
|
|
4018
|
+
IconButton as IconButton2,
|
|
4181
4019
|
Row,
|
|
4182
4020
|
RowList,
|
|
4183
4021
|
ScrollArea,
|
|
4184
4022
|
SegmentedControl,
|
|
4185
4023
|
StatusBar as StatusBar2,
|
|
4186
|
-
TextButton,
|
|
4024
|
+
TextButton as TextButton2,
|
|
4187
4025
|
Toolbar as Toolbar2,
|
|
4188
4026
|
ToolbarGroup as ToolbarGroup2
|
|
4189
4027
|
} from "@xenosystem/components/chrome";
|
|
@@ -4222,7 +4060,7 @@ function CalendarPanelView({
|
|
|
4222
4060
|
{
|
|
4223
4061
|
left: /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
4224
4062
|
/* @__PURE__ */ jsx5(
|
|
4225
|
-
|
|
4063
|
+
IconButton2,
|
|
4226
4064
|
{
|
|
4227
4065
|
icon: /* @__PURE__ */ jsx5(ChevronGlyph, { direction: "left" }),
|
|
4228
4066
|
label: "Previous",
|
|
@@ -4230,14 +4068,14 @@ function CalendarPanelView({
|
|
|
4230
4068
|
}
|
|
4231
4069
|
),
|
|
4232
4070
|
/* @__PURE__ */ jsx5(
|
|
4233
|
-
|
|
4071
|
+
IconButton2,
|
|
4234
4072
|
{
|
|
4235
4073
|
icon: /* @__PURE__ */ jsx5(ChevronGlyph, { direction: "right" }),
|
|
4236
4074
|
label: "Next",
|
|
4237
4075
|
onClick: () => controller.navigate(1)
|
|
4238
4076
|
}
|
|
4239
4077
|
),
|
|
4240
|
-
/* @__PURE__ */ jsx5(
|
|
4078
|
+
/* @__PURE__ */ jsx5(TextButton2, { onClick: () => controller.goToToday(), children: "Today" }),
|
|
4241
4079
|
/* @__PURE__ */ jsx5("span", { style: { fontSize: 11, opacity: 0.8 }, children: controller.anchorKey().slice(0, 7) })
|
|
4242
4080
|
] }),
|
|
4243
4081
|
right: /* @__PURE__ */ jsxs4(ToolbarGroup2, { end: true, children: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenosystem/blocks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@duckdb/duckdb-wasm": ">=1.28.0",
|
|
62
62
|
"@xenosystem/block-sdk": "^0.3.0",
|
|
63
|
-
"@xenosystem/components": ">=0.
|
|
63
|
+
"@xenosystem/components": ">=0.10.2 <1",
|
|
64
64
|
"@xenosystem/data-core": "^0.1.0",
|
|
65
65
|
"@xenosystem/elements-react": ">=0.0.1",
|
|
66
66
|
"@xenosystem/time-core": "^0.1.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@types/react": "^19.0.0",
|
|
77
77
|
"@types/react-dom": "^19.0.0",
|
|
78
78
|
"@xenosystem/block-sdk": "^0.3.1",
|
|
79
|
-
"@xenosystem/components": "^0.
|
|
79
|
+
"@xenosystem/components": "^0.10.2",
|
|
80
80
|
"@xenosystem/data-core": "^0.1.0",
|
|
81
81
|
"@xenosystem/elements-react": "0.0.1",
|
|
82
82
|
"@xenosystem/time-core": "^0.1.0",
|