@processengine/uikit 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.0] - 2026-06-09
8
+
9
+ ### Добавлено
10
+ - Router-agnostic примитивы `BackLink`, `PageLayout`, `PageShell`.
11
+ - Generic `ServerControl` без backend-specific логики.
12
+ - `StatusBadge`, `InfoGrid`, `InfoItem`, `DataCard` для переиспользуемых карточек и метаданных.
13
+
14
+ ### Изменено
15
+ - `PageHeader` получил `className` и настраиваемый `titleId`.
16
+
7
17
  ## [0.1.0] - 2026-06-09
8
18
 
9
19
  ### Добавлено
package/README.md CHANGED
@@ -4,17 +4,7 @@ Shared UI kit for ProcessEngine interfaces: orchestrator admin UI, Rules UI, Flo
4
4
 
5
5
  ## Install
6
6
 
7
- Before the first npm release, consumers can use a local file dependency:
8
-
9
- ```json
10
- {
11
- "dependencies": {
12
- "@processengine/uikit": "file:../uikit"
13
- }
14
- }
15
- ```
16
-
17
- After publication, pin exact versions in production consumers:
7
+ Pin exact versions in production consumers:
18
8
 
19
9
  ```json
20
10
  {
@@ -46,7 +36,8 @@ The sandbox bundle is exported as `@processengine/uikit/sandbox.css`; consuming
46
36
  import { Tabs, JsonPanel, CopyableValue } from "@processengine/uikit";
47
37
  ```
48
38
 
49
- The React layer intentionally does not depend on routing. Consumers keep their own router-specific links and page shells.
39
+ The React layer intentionally does not depend on routing or backend clients.
40
+ Consumers keep their own router-specific links and backend-specific state.
50
41
 
51
42
  ## Release Process
52
43
 
@@ -391,6 +391,186 @@
391
391
  color: var(--surface-card);
392
392
  }
393
393
 
394
+ .app-status-badge {
395
+ display: inline-flex;
396
+ align-items: center;
397
+ justify-content: center;
398
+ min-block-size: 2.05rem;
399
+ padding: 0.35rem 0.75rem;
400
+ border: 0.0625rem solid var(--status-neutral-border);
401
+ border-radius: 999px;
402
+ background: var(--status-neutral-bg);
403
+ color: var(--status-neutral-text);
404
+ font-size: 0.78rem;
405
+ line-height: 1;
406
+ font-weight: 750;
407
+ white-space: nowrap;
408
+ }
409
+
410
+ .app-status-badge--success {
411
+ border-color: var(--status-success-border);
412
+ background: var(--status-success-bg);
413
+ color: var(--status-success-text);
414
+ }
415
+
416
+ .app-status-badge--error {
417
+ border-color: var(--status-error-border);
418
+ background: var(--status-error-bg);
419
+ color: var(--status-error-text);
420
+ }
421
+
422
+ .app-status-badge--warning {
423
+ border-color: var(--status-warning-border);
424
+ background: var(--status-warning-bg);
425
+ color: var(--status-warning-text);
426
+ }
427
+
428
+ .app-status-badge--neutral {
429
+ border-color: var(--status-neutral-border);
430
+ background: var(--status-neutral-bg);
431
+ color: var(--status-neutral-text);
432
+ }
433
+
434
+ .app-data-card {
435
+ padding: 1rem;
436
+ border: 0.0625rem solid var(--border-color);
437
+ border-radius: var(--radius-lg);
438
+ background: var(--surface-card);
439
+ box-shadow: var(--shadow-sm);
440
+ }
441
+
442
+ .app-data-card--success {
443
+ border-color: var(--status-success-border);
444
+ background: var(--status-success-bg);
445
+ }
446
+
447
+ .app-data-card--error {
448
+ border-color: var(--status-error-border);
449
+ background: var(--status-error-bg);
450
+ }
451
+
452
+ .app-data-card--warning {
453
+ border-color: var(--status-warning-border);
454
+ background: var(--status-warning-bg);
455
+ }
456
+
457
+ .app-data-card--neutral {
458
+ border-color: var(--status-neutral-border);
459
+ background: var(--status-neutral-bg);
460
+ }
461
+
462
+ .app-data-card__header {
463
+ display: flex;
464
+ justify-content: space-between;
465
+ gap: 1rem;
466
+ margin-bottom: 0.875rem;
467
+ }
468
+
469
+ .app-data-card__heading {
470
+ min-width: 0;
471
+ }
472
+
473
+ .app-data-card__eyebrow {
474
+ margin-bottom: 0.2rem;
475
+ color: var(--text-faint);
476
+ font-size: 0.68rem;
477
+ line-height: 1.2;
478
+ font-weight: 800;
479
+ letter-spacing: 0.08em;
480
+ text-transform: uppercase;
481
+ }
482
+
483
+ .app-data-card__title {
484
+ color: var(--text-strong);
485
+ font-size: 1rem;
486
+ line-height: 1.2;
487
+ font-weight: 800;
488
+ letter-spacing: -0.02em;
489
+ }
490
+
491
+ .app-data-card__subtitle {
492
+ margin-top: 0.35rem;
493
+ color: var(--text-dim);
494
+ font-size: 0.9rem;
495
+ line-height: 1.45;
496
+ }
497
+
498
+ .app-data-card__aside {
499
+ flex: 0 0 auto;
500
+ }
501
+
502
+ .app-data-card__body {
503
+ min-width: 0;
504
+ }
505
+
506
+ .app-data-card__footer {
507
+ margin-top: 0.875rem;
508
+ padding-top: 0.875rem;
509
+ border-top: 0.0625rem solid var(--border-color);
510
+ }
511
+
512
+ .app-info-grid {
513
+ display: grid;
514
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
515
+ gap: 1rem 1.5rem;
516
+ }
517
+
518
+ .app-info-grid--compact {
519
+ gap: 0.75rem 1rem;
520
+ }
521
+
522
+ .app-info-item {
523
+ min-width: 0;
524
+ }
525
+
526
+ .app-info-item__label {
527
+ display: block;
528
+ margin-bottom: 0.28rem;
529
+ color: var(--text-faint);
530
+ font-size: 0.68rem;
531
+ line-height: 1.2;
532
+ font-weight: 800;
533
+ letter-spacing: 0.08em;
534
+ text-transform: uppercase;
535
+ }
536
+
537
+ .app-info-item__value {
538
+ margin: 0;
539
+ color: var(--text-strong);
540
+ font-size: 0.88rem;
541
+ line-height: 1.35;
542
+ font-weight: 750;
543
+ overflow-wrap: anywhere;
544
+ }
545
+
546
+ .app-info-item__description {
547
+ margin: 0.3rem 0 0;
548
+ color: var(--text-dim);
549
+ font-size: 0.82rem;
550
+ line-height: 1.35;
551
+ overflow-wrap: anywhere;
552
+ }
553
+
554
+ .app-info-item--tone-success .app-info-item__value,
555
+ .app-info-item--tone-success .app-info-item__description {
556
+ color: var(--status-success-text);
557
+ }
558
+
559
+ .app-info-item--tone-error .app-info-item__value,
560
+ .app-info-item--tone-error .app-info-item__description {
561
+ color: var(--status-error-text);
562
+ }
563
+
564
+ .app-info-item--tone-warning .app-info-item__value,
565
+ .app-info-item--tone-warning .app-info-item__description {
566
+ color: var(--status-warning-text);
567
+ }
568
+
569
+ .app-info-item--tone-neutral .app-info-item__value,
570
+ .app-info-item--tone-neutral .app-info-item__description {
571
+ color: var(--status-neutral-text);
572
+ }
573
+
394
574
  .app-empty-text {
395
575
  font-size: 0.95rem;
396
576
  line-height: 1.6;
@@ -0,0 +1,9 @@
1
+ type BackLinkProps = {
2
+ label: string;
3
+ href?: string;
4
+ className?: string;
5
+ onClick?: () => void;
6
+ };
7
+ export declare function BackLink({ label, href, className, onClick }: BackLinkProps): import("react").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=BackLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackLink.d.ts","sourceRoot":"","sources":["../../src/react/BackLink.tsx"],"names":[],"mappings":"AAEA,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAqBF,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,aAAa,+BAyB1E"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "./cn";
3
+ function BackIcon() {
4
+ return (_jsx("svg", { "aria-hidden": "true", className: "app-back-link__icon", fill: "none", viewBox: "0 0 20 20", children: _jsx("path", { d: "M12.5 4.5 7 10l5.5 5.5", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" }) }));
5
+ }
6
+ export function BackLink({ label, href, className, onClick }) {
7
+ const content = (_jsxs(_Fragment, { children: [_jsx(BackIcon, {}), _jsx("span", { children: label })] }));
8
+ if (href) {
9
+ return (_jsx("a", { className: cn("app-back-link", className), href: href, onClick: onClick, children: content }));
10
+ }
11
+ return (_jsx("button", { className: cn("app-back-link", className), type: "button", onClick: onClick, children: content }));
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from "react";
2
+ type DataCardProps = {
3
+ children: ReactNode;
4
+ title?: ReactNode;
5
+ eyebrow?: ReactNode;
6
+ subtitle?: ReactNode;
7
+ aside?: ReactNode;
8
+ footer?: ReactNode;
9
+ className?: string;
10
+ tone?: "success" | "error" | "neutral" | "warning";
11
+ };
12
+ export declare function DataCard({ children, title, eyebrow, subtitle, aside, footer, className, tone, }: DataCardProps): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=DataCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataCard.d.ts","sourceRoot":"","sources":["../../src/react/DataCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CACpD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EACT,IAAI,GACL,EAAE,aAAa,+BAmBf"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "./cn";
3
+ export function DataCard({ children, title, eyebrow, subtitle, aside, footer, className, tone, }) {
4
+ const hasHeader = eyebrow || title || subtitle || aside;
5
+ return (_jsxs("article", { className: cn("app-data-card", tone && `app-data-card--${tone}`, className), children: [hasHeader ? (_jsxs("header", { className: "app-data-card__header", children: [_jsxs("div", { className: "app-data-card__heading", children: [eyebrow ? _jsx("p", { className: "app-data-card__eyebrow", children: eyebrow }) : null, title ? _jsx("h2", { className: "app-data-card__title", children: title }) : null, subtitle ? _jsx("p", { className: "app-data-card__subtitle", children: subtitle }) : null] }), aside ? _jsx("div", { className: "app-data-card__aside", children: aside }) : null] })) : null, _jsx("div", { className: "app-data-card__body", children: children }), footer ? _jsx("footer", { className: "app-data-card__footer", children: footer }) : null] }));
6
+ }
@@ -0,0 +1,18 @@
1
+ import type { ReactNode } from "react";
2
+ type InfoGridProps = {
3
+ children?: ReactNode;
4
+ items?: InfoItemData[];
5
+ className?: string;
6
+ compact?: boolean;
7
+ };
8
+ export type InfoItemData = {
9
+ label: ReactNode;
10
+ value: ReactNode;
11
+ description?: ReactNode;
12
+ copyValue?: string;
13
+ tone?: "success" | "error" | "neutral" | "warning";
14
+ };
15
+ export declare function InfoGrid({ children, items, className, compact, }: InfoGridProps): import("react").JSX.Element;
16
+ export declare function InfoItem({ label, value, description, copyValue, tone, }: InfoItemData): import("react").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=InfoGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InfoGrid.d.ts","sourceRoot":"","sources":["../../src/react/InfoGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CACpD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,OAAe,GAChB,EAAE,aAAa,+BAgBf;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,WAAW,EACX,SAAS,EACT,IAAI,GACL,EAAE,YAAY,+BAYd"}
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CopyableValue } from "./CopyableValue";
3
+ import { cn } from "./cn";
4
+ export function InfoGrid({ children, items, className, compact = false, }) {
5
+ return (_jsxs("dl", { className: cn("app-info-grid", compact && "app-info-grid--compact", className), children: [items?.map((item, index) => (_jsx(InfoItem, { label: item.label, value: item.value, description: item.description, copyValue: item.copyValue, tone: item.tone }, `${String(item.label)}-${index}`))), children] }));
6
+ }
7
+ export function InfoItem({ label, value, description, copyValue, tone, }) {
8
+ return (_jsxs("div", { className: cn("app-info-item", tone && `app-info-item--tone-${tone}`), children: [_jsx("dt", { className: "app-info-item__label", children: label }), _jsx("dd", { className: "app-info-item__value", children: copyValue ? _jsx(CopyableValue, { value: copyValue }) : value }), description ? (_jsx("dd", { className: "app-info-item__description", children: description })) : null] }));
9
+ }
@@ -4,7 +4,9 @@ type PageHeaderProps = {
4
4
  subtitle?: ReactNode;
5
5
  eyebrow?: string;
6
6
  detail?: boolean;
7
+ className?: string;
8
+ titleId?: string;
7
9
  };
8
- export declare function PageHeader({ title, subtitle, eyebrow, detail }: PageHeaderProps): import("react").JSX.Element;
10
+ export declare function PageHeader({ title, subtitle, eyebrow, detail, className, titleId, }: PageHeaderProps): import("react").JSX.Element;
9
11
  export {};
10
12
  //# sourceMappingURL=PageHeader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageHeader.d.ts","sourceRoot":"","sources":["../../src/react/PageHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,eAAe,+BAU/E"}
1
+ {"version":3,"file":"PageHeader.d.ts","sourceRoot":"","sources":["../../src/react/PageHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,EACN,SAAS,EACT,OAAsB,GACvB,EAAE,eAAe,+BAgBjB"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "./cn";
3
- export function PageHeader({ title, subtitle, eyebrow, detail }) {
4
- return (_jsxs("header", { className: cn("app-page-header", detail && "app-page-header--detail"), children: [eyebrow ? _jsx("div", { className: "app-page-header__eyebrow", children: eyebrow }) : null, _jsx("h1", { className: "app-page-header__title", id: "page-title", children: title }), subtitle ? _jsx("div", { className: "app-page-header__subtitle", children: subtitle }) : null] }));
3
+ export function PageHeader({ title, subtitle, eyebrow, detail, className, titleId = "page-title", }) {
4
+ return (_jsxs("header", { className: cn("app-page-header", detail && "app-page-header--detail", className), children: [eyebrow ? _jsx("div", { className: "app-page-header__eyebrow", children: eyebrow }) : null, _jsx("h1", { className: "app-page-header__title", id: titleId, children: title }), subtitle ? _jsx("div", { className: "app-page-header__subtitle", children: subtitle }) : null] }));
5
5
  }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from "react";
2
+ type PageLayoutProps = {
3
+ children: ReactNode;
4
+ toolbar?: ReactNode;
5
+ className?: string;
6
+ frameClassName?: string;
7
+ shellClassName?: string;
8
+ labelledBy?: string;
9
+ };
10
+ export declare function PageLayout({ children, toolbar, className, frameClassName, shellClassName, labelledBy, }: PageLayoutProps): import("react").JSX.Element;
11
+ export declare const PageShell: typeof PageLayout;
12
+ export {};
13
+ //# sourceMappingURL=PageLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageLayout.d.ts","sourceRoot":"","sources":["../../src/react/PageLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,EACP,SAAS,EACT,cAAc,EACd,cAAc,EACd,UAAU,GACX,EAAE,eAAe,+BAcjB;AAED,eAAO,MAAM,SAAS,mBAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "./cn";
3
+ export function PageLayout({ children, toolbar, className, frameClassName, shellClassName, labelledBy, }) {
4
+ return (_jsx("main", { className: cn("app-page", className), children: _jsxs("div", { className: cn("app-shell-frame", frameClassName), children: [toolbar, _jsx("section", { className: cn("app-shell", shellClassName), "aria-labelledby": labelledBy, children: children })] }) }));
5
+ }
6
+ export const PageShell = PageLayout;
@@ -0,0 +1,14 @@
1
+ type ServerControlProps = {
2
+ label: string;
3
+ value: string;
4
+ onSave: (value: string) => void;
5
+ placeholder?: string;
6
+ emptyValueLabel?: string;
7
+ className?: string;
8
+ inputAriaLabel?: string;
9
+ normalize?: (value: string) => string | null;
10
+ saveOnBlur?: boolean;
11
+ };
12
+ export declare function ServerControl({ label, value, onSave, placeholder, emptyValueLabel, className, inputAriaLabel, normalize, saveOnBlur, }: ServerControlProps): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=ServerControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerControl.d.ts","sourceRoot":"","sources":["../../src/react/ServerControl.tsx"],"names":[],"mappings":"AASA,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAW,EACX,eAA+B,EAC/B,SAAS,EACT,cAAc,EACd,SAA2C,EAC3C,UAAkB,GACnB,EAAE,kBAAkB,+BAiGpB"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState, } from "react";
3
+ import { cn } from "./cn";
4
+ export function ServerControl({ label, value, onSave, placeholder, emptyValueLabel = "same-origin", className, inputAriaLabel, normalize = (nextValue) => nextValue.trim(), saveOnBlur = false, }) {
5
+ const [isEditing, setIsEditing] = useState(false);
6
+ const [draftValue, setDraftValue] = useState(value);
7
+ const [hasError, setHasError] = useState(false);
8
+ const inputRef = useRef(null);
9
+ useEffect(() => {
10
+ if (!isEditing) {
11
+ setDraftValue(value);
12
+ }
13
+ }, [isEditing, value]);
14
+ useEffect(() => {
15
+ if (isEditing) {
16
+ inputRef.current?.focus();
17
+ inputRef.current?.select();
18
+ }
19
+ }, [isEditing]);
20
+ function startEditing() {
21
+ setDraftValue(value);
22
+ setHasError(false);
23
+ setIsEditing(true);
24
+ }
25
+ function stopEditing() {
26
+ setDraftValue(value);
27
+ setHasError(false);
28
+ setIsEditing(false);
29
+ }
30
+ function saveValue() {
31
+ const normalizedValue = normalize(draftValue);
32
+ if (normalizedValue === null) {
33
+ setHasError(true);
34
+ return;
35
+ }
36
+ onSave(normalizedValue);
37
+ setHasError(false);
38
+ setIsEditing(false);
39
+ }
40
+ function handleSubmit(event) {
41
+ event.preventDefault();
42
+ saveValue();
43
+ }
44
+ function handleKeyDown(event) {
45
+ if (event.key === "Escape") {
46
+ event.preventDefault();
47
+ stopEditing();
48
+ }
49
+ }
50
+ if (isEditing) {
51
+ return (_jsx("form", { className: "app-server-control__form", onSubmit: handleSubmit, children: _jsxs("label", { className: "app-server-control app-server-control--editing", children: [_jsx("span", { className: "app-server-control__label", children: label }), _jsx("input", { ref: inputRef, className: cn("app-server-control__input", hasError && "app-server-control__input--error"), value: draftValue, onBlur: saveOnBlur ? saveValue : undefined, onChange: (event) => {
52
+ setDraftValue(event.target.value);
53
+ if (hasError) {
54
+ setHasError(false);
55
+ }
56
+ }, onKeyDown: handleKeyDown, placeholder: placeholder, "aria-label": inputAriaLabel ?? label })] }) }));
57
+ }
58
+ return (_jsxs("button", { className: cn("app-server-control", className), type: "button", onClick: startEditing, title: value, children: [_jsx("span", { className: "app-server-control__label", children: label }), _jsx("span", { className: "app-server-control__value", children: value || emptyValueLabel })] }));
59
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from "react";
2
+ export type StatusBadgeTone = "success" | "error" | "neutral" | "warning";
3
+ type StatusBadgeProps = {
4
+ label: ReactNode;
5
+ tone?: StatusBadgeTone;
6
+ className?: string;
7
+ };
8
+ export declare function StatusBadge({ label, tone, className, }: StatusBadgeProps): import("react").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=StatusBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBadge.d.ts","sourceRoot":"","sources":["../../src/react/StatusBadge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAE1E,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,IAAgB,EAChB,SAAS,GACV,EAAE,gBAAgB,+BAYlB"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "./cn";
3
+ export function StatusBadge({ label, tone = "neutral", className, }) {
4
+ return (_jsx("span", { className: cn("app-status-badge", `app-status-badge--${tone}`, className), children: label }));
5
+ }
@@ -1,9 +1,15 @@
1
+ export { BackLink } from "./BackLink";
1
2
  export { cn, type ClassValue } from "./cn";
2
3
  export { CopyableValue } from "./CopyableValue";
4
+ export { DataCard } from "./DataCard";
5
+ export { InfoGrid, InfoItem, type InfoItemData } from "./InfoGrid";
3
6
  export { JsonExplorer } from "./JsonExplorer";
4
7
  export { JsonPanel } from "./JsonPanel";
8
+ export { PageLayout, PageShell } from "./PageLayout";
5
9
  export { PageHeader } from "./PageHeader";
6
10
  export { SearchInput } from "./SearchInput";
11
+ export { ServerControl } from "./ServerControl";
7
12
  export { StateCard } from "./StateCard";
13
+ export { StatusBadge, type StatusBadgeTone } from "./StatusBadge";
8
14
  export { Tabs, type TabOption } from "./Tabs";
9
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC"}
@@ -1,8 +1,14 @@
1
+ export { BackLink } from "./BackLink";
1
2
  export { cn } from "./cn";
2
3
  export { CopyableValue } from "./CopyableValue";
4
+ export { DataCard } from "./DataCard";
5
+ export { InfoGrid, InfoItem } from "./InfoGrid";
3
6
  export { JsonExplorer } from "./JsonExplorer";
4
7
  export { JsonPanel } from "./JsonPanel";
8
+ export { PageLayout, PageShell } from "./PageLayout";
5
9
  export { PageHeader } from "./PageHeader";
6
10
  export { SearchInput } from "./SearchInput";
11
+ export { ServerControl } from "./ServerControl";
7
12
  export { StateCard } from "./StateCard";
13
+ export { StatusBadge } from "./StatusBadge";
8
14
  export { Tabs } from "./Tabs";
package/dist/styles.css CHANGED
@@ -33,6 +33,9 @@
33
33
  --status-neutral-bg: #f1f5f9;
34
34
  --status-neutral-border: #cbd5e1;
35
35
  --status-neutral-text: #334155;
36
+ --status-warning-bg: #fffbeb;
37
+ --status-warning-border: #fde68a;
38
+ --status-warning-text: #92400e;
36
39
 
37
40
  --stage-success-bg: #f0fdf4;
38
41
  --stage-success-border: #bbf7d0;
@@ -526,6 +529,186 @@ a {
526
529
  color: var(--surface-card);
527
530
  }
528
531
 
532
+ .app-status-badge {
533
+ display: inline-flex;
534
+ align-items: center;
535
+ justify-content: center;
536
+ min-block-size: 2.05rem;
537
+ padding: 0.35rem 0.75rem;
538
+ border: 0.0625rem solid var(--status-neutral-border);
539
+ border-radius: 999px;
540
+ background: var(--status-neutral-bg);
541
+ color: var(--status-neutral-text);
542
+ font-size: 0.78rem;
543
+ line-height: 1;
544
+ font-weight: 750;
545
+ white-space: nowrap;
546
+ }
547
+
548
+ .app-status-badge--success {
549
+ border-color: var(--status-success-border);
550
+ background: var(--status-success-bg);
551
+ color: var(--status-success-text);
552
+ }
553
+
554
+ .app-status-badge--error {
555
+ border-color: var(--status-error-border);
556
+ background: var(--status-error-bg);
557
+ color: var(--status-error-text);
558
+ }
559
+
560
+ .app-status-badge--warning {
561
+ border-color: var(--status-warning-border);
562
+ background: var(--status-warning-bg);
563
+ color: var(--status-warning-text);
564
+ }
565
+
566
+ .app-status-badge--neutral {
567
+ border-color: var(--status-neutral-border);
568
+ background: var(--status-neutral-bg);
569
+ color: var(--status-neutral-text);
570
+ }
571
+
572
+ .app-data-card {
573
+ padding: 1rem;
574
+ border: 0.0625rem solid var(--border-color);
575
+ border-radius: var(--radius-lg);
576
+ background: var(--surface-card);
577
+ box-shadow: var(--shadow-sm);
578
+ }
579
+
580
+ .app-data-card--success {
581
+ border-color: var(--status-success-border);
582
+ background: var(--status-success-bg);
583
+ }
584
+
585
+ .app-data-card--error {
586
+ border-color: var(--status-error-border);
587
+ background: var(--status-error-bg);
588
+ }
589
+
590
+ .app-data-card--warning {
591
+ border-color: var(--status-warning-border);
592
+ background: var(--status-warning-bg);
593
+ }
594
+
595
+ .app-data-card--neutral {
596
+ border-color: var(--status-neutral-border);
597
+ background: var(--status-neutral-bg);
598
+ }
599
+
600
+ .app-data-card__header {
601
+ display: flex;
602
+ justify-content: space-between;
603
+ gap: 1rem;
604
+ margin-bottom: 0.875rem;
605
+ }
606
+
607
+ .app-data-card__heading {
608
+ min-width: 0;
609
+ }
610
+
611
+ .app-data-card__eyebrow {
612
+ margin-bottom: 0.2rem;
613
+ color: var(--text-faint);
614
+ font-size: 0.68rem;
615
+ line-height: 1.2;
616
+ font-weight: 800;
617
+ letter-spacing: 0.08em;
618
+ text-transform: uppercase;
619
+ }
620
+
621
+ .app-data-card__title {
622
+ color: var(--text-strong);
623
+ font-size: 1rem;
624
+ line-height: 1.2;
625
+ font-weight: 800;
626
+ letter-spacing: -0.02em;
627
+ }
628
+
629
+ .app-data-card__subtitle {
630
+ margin-top: 0.35rem;
631
+ color: var(--text-dim);
632
+ font-size: 0.9rem;
633
+ line-height: 1.45;
634
+ }
635
+
636
+ .app-data-card__aside {
637
+ flex: 0 0 auto;
638
+ }
639
+
640
+ .app-data-card__body {
641
+ min-width: 0;
642
+ }
643
+
644
+ .app-data-card__footer {
645
+ margin-top: 0.875rem;
646
+ padding-top: 0.875rem;
647
+ border-top: 0.0625rem solid var(--border-color);
648
+ }
649
+
650
+ .app-info-grid {
651
+ display: grid;
652
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
653
+ gap: 1rem 1.5rem;
654
+ }
655
+
656
+ .app-info-grid--compact {
657
+ gap: 0.75rem 1rem;
658
+ }
659
+
660
+ .app-info-item {
661
+ min-width: 0;
662
+ }
663
+
664
+ .app-info-item__label {
665
+ display: block;
666
+ margin-bottom: 0.28rem;
667
+ color: var(--text-faint);
668
+ font-size: 0.68rem;
669
+ line-height: 1.2;
670
+ font-weight: 800;
671
+ letter-spacing: 0.08em;
672
+ text-transform: uppercase;
673
+ }
674
+
675
+ .app-info-item__value {
676
+ margin: 0;
677
+ color: var(--text-strong);
678
+ font-size: 0.88rem;
679
+ line-height: 1.35;
680
+ font-weight: 750;
681
+ overflow-wrap: anywhere;
682
+ }
683
+
684
+ .app-info-item__description {
685
+ margin: 0.3rem 0 0;
686
+ color: var(--text-dim);
687
+ font-size: 0.82rem;
688
+ line-height: 1.35;
689
+ overflow-wrap: anywhere;
690
+ }
691
+
692
+ .app-info-item--tone-success .app-info-item__value,
693
+ .app-info-item--tone-success .app-info-item__description {
694
+ color: var(--status-success-text);
695
+ }
696
+
697
+ .app-info-item--tone-error .app-info-item__value,
698
+ .app-info-item--tone-error .app-info-item__description {
699
+ color: var(--status-error-text);
700
+ }
701
+
702
+ .app-info-item--tone-warning .app-info-item__value,
703
+ .app-info-item--tone-warning .app-info-item__description {
704
+ color: var(--status-warning-text);
705
+ }
706
+
707
+ .app-info-item--tone-neutral .app-info-item__value,
708
+ .app-info-item--tone-neutral .app-info-item__description {
709
+ color: var(--status-neutral-text);
710
+ }
711
+
529
712
  .app-empty-text {
530
713
  font-size: 0.95rem;
531
714
  line-height: 1.6;
package/dist/tokens.css CHANGED
@@ -32,6 +32,9 @@
32
32
  --status-neutral-bg: #f1f5f9;
33
33
  --status-neutral-border: #cbd5e1;
34
34
  --status-neutral-text: #334155;
35
+ --status-warning-bg: #fffbeb;
36
+ --status-warning-border: #fde68a;
37
+ --status-warning-text: #92400e;
35
38
 
36
39
  --stage-success-bg: #f0fdf4;
37
40
  --stage-success-border: #bbf7d0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processengine/uikit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Shared UI kit for ProcessEngine admin, rules, and sandbox interfaces",
5
5
  "type": "module",
6
6
  "main": "./dist/react/index.js",