@kerfjs/ui 5.0.0-beta.18 → 5.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +114 -3
  2. package/ai/application-ui-diagnostic-ids-v1.json +92 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +101 -0
  12. package/ai/compile-time-contracts-v1.schema.json +49 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-v2-overrides.json +326 -0
  16. package/ai/component-catalog-v2.d.ts +67 -0
  17. package/ai/component-catalog-v2.json +4441 -0
  18. package/ai/component-catalog-v2.schema.json +246 -0
  19. package/ai/component-catalog.json +150 -6
  20. package/ai/public-api-signatures-v1.md +294 -64
  21. package/ai/skill.md +41 -5
  22. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  23. package/analyzer/cli.mjs +46 -0
  24. package/analyzer/index.d.mts +45 -0
  25. package/analyzer/index.mjs +743 -0
  26. package/analyzer/report.schema.json +66 -0
  27. package/dist/browser/pane.js +3 -0
  28. package/dist/browser/sunken-panel.js +3 -0
  29. package/dist/catalog-resources.d.ts +34 -0
  30. package/dist/catalog-resources.js +22 -0
  31. package/dist/catalog-resources.js.map +1 -0
  32. package/dist/catalog.d.ts +21 -3
  33. package/dist/catalog.js +239 -210
  34. package/dist/catalog.js.map +1 -1
  35. package/dist/{chunk-ZK2G3VR5.js → chunk-5VTB2BKP.js} +1 -1
  36. package/dist/chunk-5VTB2BKP.js.map +1 -0
  37. package/dist/{chunk-S3HKPI7I.js → chunk-7KEUJIIC.js} +1 -1
  38. package/dist/chunk-7KEUJIIC.js.map +1 -0
  39. package/dist/{chunk-NVWXKU37.js → chunk-AASLYRGE.js} +1 -1
  40. package/dist/chunk-AASLYRGE.js.map +1 -0
  41. package/dist/{chunk-ENVTNLYC.js → chunk-CN2XNTAM.js} +6 -6
  42. package/dist/chunk-CN2XNTAM.js.map +1 -0
  43. package/dist/{chunk-QIRXYKCE.js → chunk-DSNIYOZ3.js} +3 -2
  44. package/dist/chunk-DSNIYOZ3.js.map +1 -0
  45. package/dist/chunk-JRKSK2HX.js +79 -0
  46. package/dist/chunk-JRKSK2HX.js.map +1 -0
  47. package/dist/{chunk-U5IFGQCD.js → chunk-K57KRAOV.js} +1 -1
  48. package/dist/chunk-K57KRAOV.js.map +1 -0
  49. package/dist/{chunk-ZVI5YST2.js → chunk-M7JBER5U.js} +1 -1
  50. package/dist/chunk-M7JBER5U.js.map +1 -0
  51. package/dist/{chunk-43FUQH35.js → chunk-OHU6CI22.js} +2 -2
  52. package/dist/{chunk-43FUQH35.js.map → chunk-OHU6CI22.js.map} +1 -1
  53. package/dist/{chunk-4TRDV6RL.js → chunk-OZWU5ZPZ.js} +1 -1
  54. package/dist/chunk-OZWU5ZPZ.js.map +1 -0
  55. package/dist/{chunk-JTHUXDN2.js → chunk-RYRIFZCT.js} +3 -3
  56. package/dist/chunk-RYRIFZCT.js.map +1 -0
  57. package/dist/{chunk-6ETZKKAE.js → chunk-VLYV65LK.js} +1 -1
  58. package/dist/chunk-VLYV65LK.js.map +1 -0
  59. package/dist/chunk-W4CXQYSG.js +23 -0
  60. package/dist/chunk-W4CXQYSG.js.map +1 -0
  61. package/dist/{chunk-S3PCZ7NV.js → chunk-W7YD6E4N.js} +1 -1
  62. package/dist/chunk-W7YD6E4N.js.map +1 -0
  63. package/dist/index.d.ts +6 -4
  64. package/dist/index.js +14 -12
  65. package/dist/list-header.d.ts +29 -8
  66. package/dist/list-header.js +1 -1
  67. package/dist/nav-stack.js +1 -1
  68. package/dist/pane.d.ts +49 -0
  69. package/dist/pane.js +4 -0
  70. package/dist/pane.js.map +1 -0
  71. package/dist/panel-header.d.ts +9 -3
  72. package/dist/panel-header.js +1 -1
  73. package/dist/segmented-control.d.ts +6 -6
  74. package/dist/segmented-control.js +1 -1
  75. package/dist/select.d.ts +10 -4
  76. package/dist/select.js +1 -1
  77. package/dist/split-view.js +2 -2
  78. package/dist/state-banner.d.ts +3 -2
  79. package/dist/state-banner.js +1 -1
  80. package/dist/styles/catalog.css +6 -6
  81. package/dist/styles/layout.css +2 -20
  82. package/dist/styles/pane.css +62 -0
  83. package/dist/styles/segmented-control.css +3 -7
  84. package/dist/styles/sunken-panel.css +18 -0
  85. package/dist/sunken-panel.d.ts +16 -0
  86. package/dist/sunken-panel.js +3 -0
  87. package/dist/sunken-panel.js.map +1 -0
  88. package/dist/tab-bar.d.ts +3 -2
  89. package/dist/tab-bar.js +1 -1
  90. package/dist/tab-scaffold.d.ts +6 -6
  91. package/dist/tab-scaffold.js.map +1 -1
  92. package/dist/token-search-field.d.ts +25 -9
  93. package/dist/token-search-field.js +1 -1
  94. package/dist/toolbar-control-group.d.ts +9 -5
  95. package/dist/toolbar-control-group.js +1 -1
  96. package/dist/toolbar-text.d.ts +10 -11
  97. package/dist/toolbar-text.js +1 -1
  98. package/dist/wire-tab-bars.d.ts +5 -2
  99. package/dist/wire-tab-bars.js +1 -1
  100. package/dist/wire-token-search-fields.d.ts +11 -6
  101. package/dist/wire-token-search-fields.js +1 -1
  102. package/docs/catalog.md +186 -67
  103. package/docs/component-contract.md +102 -5
  104. package/docs/component-selection.md +9 -5
  105. package/docs/design-philosophy.md +2 -4
  106. package/docs/examples/application-ui-profile.json +60 -0
  107. package/docs/examples/component-catalog-extension-v2.json +81 -0
  108. package/docs/layout.md +42 -23
  109. package/docs/sunken-panel.md +43 -0
  110. package/docs/type-contracts.md +99 -0
  111. package/docs/ui-analyzer.md +81 -0
  112. package/docs/ui-doctor.md +77 -0
  113. package/docs/ui-evaluator.md +122 -0
  114. package/doctor/cli.mjs +115 -0
  115. package/doctor/config.schema.json +68 -0
  116. package/doctor/index.d.mts +116 -0
  117. package/doctor/index.mjs +1256 -0
  118. package/doctor/report.schema.json +118 -0
  119. package/evaluator/cli.mjs +89 -0
  120. package/evaluator/index.d.mts +90 -0
  121. package/evaluator/index.mjs +1138 -0
  122. package/evaluator/report.schema.json +152 -0
  123. package/llms.txt +40 -3
  124. package/package.json +66 -8
  125. package/ux-demo/recipes/compact-toolbar.tsx +2 -2
  126. package/ux-demo/recipes/composer-form.tsx +1 -1
  127. package/dist/chunk-4TRDV6RL.js.map +0 -1
  128. package/dist/chunk-6ETZKKAE.js.map +0 -1
  129. package/dist/chunk-ENVTNLYC.js.map +0 -1
  130. package/dist/chunk-JTHUXDN2.js.map +0 -1
  131. package/dist/chunk-NVWXKU37.js.map +0 -1
  132. package/dist/chunk-QIRXYKCE.js.map +0 -1
  133. package/dist/chunk-S3HKPI7I.js.map +0 -1
  134. package/dist/chunk-S3PCZ7NV.js.map +0 -1
  135. package/dist/chunk-U5IFGQCD.js.map +0 -1
  136. package/dist/chunk-ZK2G3VR5.js.map +0 -1
  137. package/dist/chunk-ZVI5YST2.js.map +0 -1
@@ -0,0 +1,118 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/brianwestphal/kerf/main/ui/doctor/report.schema.json",
4
+ "title": "Kerf UI doctor report",
5
+ "type": "object",
6
+ "required": [
7
+ "schemaVersion",
8
+ "tool",
9
+ "mode",
10
+ "root",
11
+ "package",
12
+ "paths",
13
+ "stages",
14
+ "diagnostics",
15
+ "suppressions",
16
+ "summary",
17
+ "exitCode",
18
+ "cache"
19
+ ],
20
+ "properties": {
21
+ "schemaVersion": { "const": 1 },
22
+ "tool": { "const": { "name": "@kerfjs/ui/doctor", "reportVersion": 1 } },
23
+ "mode": { "enum": ["full", "changed"] },
24
+ "root": { "const": "." },
25
+ "package": { "type": "string" },
26
+ "paths": { "type": "array", "items": { "type": "string" } },
27
+ "stages": { "type": "array", "items": { "$ref": "#/$defs/stage" } },
28
+ "diagnostics": {
29
+ "type": "array",
30
+ "items": { "$ref": "#/$defs/diagnostic" }
31
+ },
32
+ "suppressions": {
33
+ "type": "array",
34
+ "items": {
35
+ "allOf": [
36
+ { "$ref": "#/$defs/diagnostic" },
37
+ {
38
+ "type": "object",
39
+ "required": ["suppression"],
40
+ "properties": {
41
+ "suppression": {
42
+ "type": "object",
43
+ "required": ["id", "rationale"],
44
+ "properties": {
45
+ "id": { "type": "string" },
46
+ "rationale": { "type": "string" }
47
+ },
48
+ "additionalProperties": false
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ }
54
+ },
55
+ "summary": {
56
+ "type": "object",
57
+ "required": ["errors", "warnings", "review", "suppressed"],
58
+ "properties": {
59
+ "errors": { "type": "integer", "minimum": 0 },
60
+ "warnings": { "type": "integer", "minimum": 0 },
61
+ "review": { "type": "integer", "minimum": 0 },
62
+ "suppressed": { "type": "integer", "minimum": 0 }
63
+ },
64
+ "additionalProperties": false
65
+ },
66
+ "exitCode": { "enum": [0, 1, 2, 130] },
67
+ "cache": {
68
+ "type": "object",
69
+ "required": ["hit", "key"],
70
+ "properties": {
71
+ "hit": { "type": "boolean" },
72
+ "key": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
73
+ },
74
+ "additionalProperties": false
75
+ }
76
+ },
77
+ "additionalProperties": false,
78
+ "$defs": {
79
+ "stage": {
80
+ "type": "object",
81
+ "required": ["id", "status"],
82
+ "properties": {
83
+ "id": { "type": "string" },
84
+ "status": {
85
+ "enum": [
86
+ "ran",
87
+ "cached",
88
+ "skipped",
89
+ "unavailable",
90
+ "failed",
91
+ "cancelled"
92
+ ]
93
+ },
94
+ "detail": { "type": "string" }
95
+ },
96
+ "additionalProperties": false
97
+ },
98
+ "diagnostic": {
99
+ "type": "object",
100
+ "required": ["id", "severity", "stage", "message"],
101
+ "properties": {
102
+ "id": { "type": "string" },
103
+ "severity": { "enum": ["error", "warning", "review", "info"] },
104
+ "stage": { "type": "string" },
105
+ "message": { "type": "string" },
106
+ "location": { "type": "object" },
107
+ "dom": { "type": "object" },
108
+ "evidence": {},
109
+ "catalogFacts": {},
110
+ "documentation": { "type": "string" },
111
+ "action": { "type": "string" },
112
+ "sources": { "type": "array", "items": { "type": "string" } },
113
+ "suppression": { "type": "object" }
114
+ },
115
+ "additionalProperties": false
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ import console from 'node:console';
4
+ import { resolve } from 'node:path';
5
+ import process from 'node:process';
6
+
7
+ import { evaluateUi, formatUiEvaluationText } from './index.mjs';
8
+
9
+ const args = process.argv.slice(2);
10
+ const take = (name) => {
11
+ const index = args.indexOf(name);
12
+ if (index < 0) return undefined;
13
+ const value = args[index + 1];
14
+ if (!value || value.startsWith('--'))
15
+ throw new Error(`${name} requires a value.`);
16
+ args.splice(index, 2);
17
+ return value;
18
+ };
19
+
20
+ try {
21
+ if (args.includes('--help') || args.includes('-h')) {
22
+ console.log(`Usage: kerf-ui-evaluate --url <running-app> [options]
23
+
24
+ Options:
25
+ --root <path> Workspace root (default: current directory)
26
+ --start <path> Profile discovery start directory (default: root)
27
+ --profile <path> Override the package-default profile
28
+ --browser <list> Comma-separated chromium,firefox,webkit
29
+ --output <directory> Evidence directory (default: kerf-ui-evidence)
30
+ --report <path> Report JSON path (default: <output>/report.json)
31
+ --timeout <ms> Per-operation timeout (default: 15000)
32
+ --settle <ms> App settle delay after navigation (default: 100)
33
+ --retention <policy> always, on-failure, or never
34
+ --format <format> text or json (default: text)
35
+ --no-fail Exit zero even when objective diagnostics fail`);
36
+ process.exit(0);
37
+ }
38
+ const url = take('--url');
39
+ const root = resolve(take('--root') ?? process.cwd());
40
+ const startDirectory = resolve(root, take('--start') ?? '.');
41
+ const packageProfile = take('--profile');
42
+ const outputDirectory = resolve(root, take('--output') ?? 'kerf-ui-evidence');
43
+ const reportValue = take('--report');
44
+ const reportPath = reportValue
45
+ ? resolve(root, reportValue)
46
+ : resolve(outputDirectory, 'report.json');
47
+ const browserValue = take('--browser');
48
+ const browsers = browserValue
49
+ ? browserValue.split(',').map((value) => value.trim())
50
+ : undefined;
51
+ const timeoutMs = Number(take('--timeout') ?? 15_000);
52
+ const settleMs = Number(take('--settle') ?? 100);
53
+ const retention = take('--retention') ?? 'on-failure';
54
+ const format = take('--format') ?? 'text';
55
+ const noFail = args.includes('--no-fail');
56
+ const unknown = args.filter((argument) => argument !== '--no-fail');
57
+ if (unknown.length)
58
+ throw new Error(`Unknown arguments: ${unknown.join(' ')}`);
59
+ if (!url) throw new Error('--url is required.');
60
+ if (!['text', 'json'].includes(format))
61
+ throw new Error('--format must be text or json.');
62
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
63
+ throw new Error('--timeout must be a positive number.');
64
+ if (!Number.isFinite(settleMs) || settleMs < 0)
65
+ throw new Error('--settle must be a non-negative number.');
66
+
67
+ const report = await evaluateUi({
68
+ url,
69
+ workspaceRoot: root,
70
+ startDirectory,
71
+ packageProfile: packageProfile && resolve(root, packageProfile),
72
+ outputDirectory,
73
+ reportPath,
74
+ browsers,
75
+ timeoutMs,
76
+ settleMs,
77
+ retention,
78
+ });
79
+ console.log(
80
+ format === 'json'
81
+ ? JSON.stringify(report, null, 2)
82
+ : formatUiEvaluationText(report),
83
+ );
84
+ console.error(`Report: ${reportPath}`);
85
+ if (!noFail && !report.summary.passed) process.exitCode = 1;
86
+ } catch (error) {
87
+ console.error(`kerf-ui-evaluate: ${error.message}`);
88
+ process.exitCode = 2;
89
+ }
@@ -0,0 +1,90 @@
1
+ export type UiEvaluationBrowser = 'chromium' | 'firefox' | 'webkit';
2
+ export type UiEvaluationRetention = 'always' | 'on-failure' | 'never';
3
+
4
+ export interface UiEvaluationContext {
5
+ id: string;
6
+ width: number;
7
+ height: number;
8
+ zoom: number;
9
+ colorScheme: 'light' | 'dark';
10
+ reducedMotion?: 'reduce' | 'no-preference';
11
+ }
12
+
13
+ export interface UiEvaluationDiagnostic {
14
+ code: `KUI-B${number}`;
15
+ severity: 'error' | 'warning';
16
+ context: string;
17
+ message: string;
18
+ repair?: string;
19
+ selector?: string;
20
+ evidence?: unknown;
21
+ }
22
+
23
+ export interface UiEvaluationReport {
24
+ schemaVersion: 1;
25
+ tool: { name: '@kerfjs/ui/evaluator'; reportVersion: 1 };
26
+ target: { url: string };
27
+ recordedAt: string;
28
+ profileFiles: string[];
29
+ contexts: Array<
30
+ UiEvaluationContext & {
31
+ browser: UiEvaluationBrowser;
32
+ evidence: unknown;
33
+ summary: { errors: number; warnings: number; passed: boolean };
34
+ }
35
+ >;
36
+ diagnostics: UiEvaluationDiagnostic[];
37
+ summary: { errors: number; warnings: number; passed: boolean };
38
+ artifacts: {
39
+ retention: UiEvaluationRetention;
40
+ files: Array<{ path: string; sha256: string }>;
41
+ };
42
+ subjectiveReview: {
43
+ status: 'not-recorded';
44
+ rubric: Array<{ id: string; prompt: string }>;
45
+ ratings: [];
46
+ note: string;
47
+ };
48
+ }
49
+
50
+ export const UI_EVALUATION_SCHEMA_VERSION: 1;
51
+ export const UI_EVALUATION_RULES: Readonly<
52
+ Record<`KUI-B${number}`, { severity: 'error' | 'warning'; title: string }>
53
+ >;
54
+ export const SUBJECTIVE_REVIEW_RUBRIC: ReadonlyArray<{
55
+ id: string;
56
+ prompt: string;
57
+ }>;
58
+ export function buildEvaluationContexts(
59
+ overrides?: UiEvaluationContext[],
60
+ ): UiEvaluationContext[];
61
+ export function contrastRatio(
62
+ foreground: string | number[],
63
+ background: string | number[],
64
+ ): number | null;
65
+ export function createEvaluationReport(options: {
66
+ target: { url: string };
67
+ profileFiles: string[];
68
+ contexts: UiEvaluationReport['contexts'];
69
+ diagnostics: UiEvaluationDiagnostic[];
70
+ artifacts: UiEvaluationReport['artifacts']['files'];
71
+ recordedAt: string;
72
+ retention: UiEvaluationRetention;
73
+ }): UiEvaluationReport;
74
+ export function evaluateUi(options: {
75
+ url: string;
76
+ workspaceRoot?: string;
77
+ startDirectory?: string;
78
+ packageProfile?: string;
79
+ outputDirectory?: string;
80
+ reportPath?: string;
81
+ browsers?: UiEvaluationBrowser[];
82
+ contexts?: UiEvaluationContext[];
83
+ timeoutMs?: number;
84
+ settleMs?: number;
85
+ retention?: UiEvaluationRetention;
86
+ recordedAt?: string;
87
+ playwright?: unknown;
88
+ signal?: AbortSignal;
89
+ }): Promise<UiEvaluationReport>;
90
+ export function formatUiEvaluationText(report: UiEvaluationReport): string;