altitude-design 0.2.0 → 0.3.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/README.md +46 -8
- package/dist/adapters/codemirror.cjs +88 -0
- package/dist/adapters/codemirror.cjs.map +7 -0
- package/dist/adapters/codemirror.js +67 -0
- package/dist/adapters/codemirror.js.map +7 -0
- package/dist/adapters/react-flow.css +102 -0
- package/dist/adapters/tiptap.css +71 -0
- package/dist/altitude.css +3165 -246
- package/dist/altitude.iife.js +33 -5
- package/dist/altitude.no-fonts.css +3165 -246
- package/dist/chart-themes.cjs +195 -0
- package/dist/chart-themes.cjs.map +7 -0
- package/dist/chart-themes.js +165 -0
- package/dist/chart-themes.js.map +7 -0
- package/dist/cli/altitude.mjs +134 -0
- package/dist/guidance/README.md +32 -0
- package/dist/guidance/agent-setup.md +22 -0
- package/dist/guidance/app-skeleton.md +17 -0
- package/dist/guidance/evidence.json +95 -0
- package/dist/guidance/index.json +493 -0
- package/dist/guidance/llms.txt +20 -0
- package/dist/guidance/manifest.json +92 -0
- package/dist/guidance/pattern.schema.json +181 -0
- package/dist/guidance/patterns/agent-action.json +77 -0
- package/dist/guidance/patterns/agent-action.md +39 -0
- package/dist/guidance/patterns/assistant-conversation.json +77 -0
- package/dist/guidance/patterns/assistant-conversation.md +50 -0
- package/dist/guidance/patterns/async-collection.json +71 -0
- package/dist/guidance/patterns/async-collection.md +29 -0
- package/dist/guidance/patterns/audit-log.json +75 -0
- package/dist/guidance/patterns/audit-log.md +27 -0
- package/dist/guidance/patterns/auth.json +86 -0
- package/dist/guidance/patterns/auth.md +29 -0
- package/dist/guidance/patterns/billing.json +80 -0
- package/dist/guidance/patterns/billing.md +29 -0
- package/dist/guidance/patterns/consequential-action.json +76 -0
- package/dist/guidance/patterns/consequential-action.md +27 -0
- package/dist/guidance/patterns/developer-settings.json +79 -0
- package/dist/guidance/patterns/developer-settings.md +29 -0
- package/dist/guidance/patterns/edit-record.json +74 -0
- package/dist/guidance/patterns/edit-record.md +51 -0
- package/dist/guidance/patterns/import.json +77 -0
- package/dist/guidance/patterns/import.md +31 -0
- package/dist/guidance/patterns/members.json +77 -0
- package/dist/guidance/patterns/members.md +27 -0
- package/dist/guidance/patterns/onboarding.json +78 -0
- package/dist/guidance/patterns/onboarding.md +31 -0
- package/dist/guidance/patterns/review-submit.json +72 -0
- package/dist/guidance/patterns/review-submit.md +27 -0
- package/dist/guidance/patterns/screen-layout.json +79 -0
- package/dist/guidance/patterns/screen-layout.md +40 -0
- package/dist/guidance/patterns/settings.json +78 -0
- package/dist/guidance/patterns/settings.md +32 -0
- package/dist/guidance/patterns/sync.json +77 -0
- package/dist/guidance/patterns/sync.md +31 -0
- package/dist/guidance/principles.md +23 -0
- package/dist/guidance/references/build/checks/agent-action-pattern.mjs +57 -0
- package/dist/guidance/references/build/checks/agent-setup.mjs +78 -0
- package/dist/guidance/references/build/checks/assistant-conversation-pattern.mjs +49 -0
- package/dist/guidance/references/build/checks/audit-log-pattern.mjs +63 -0
- package/dist/guidance/references/build/checks/auth-pattern.mjs +67 -0
- package/dist/guidance/references/build/checks/billing-pattern.mjs +63 -0
- package/dist/guidance/references/build/checks/developer-settings-pattern.mjs +76 -0
- package/dist/guidance/references/build/checks/guidance.mjs +71 -0
- package/dist/guidance/references/build/checks/import-pattern.mjs +69 -0
- package/dist/guidance/references/build/checks/members-pattern.mjs +71 -0
- package/dist/guidance/references/build/checks/onboarding-pattern.mjs +54 -0
- package/dist/guidance/references/build/checks/pattern-types.mjs +13 -0
- package/dist/guidance/references/build/checks/pattern-workflows.mjs +226 -0
- package/dist/guidance/references/build/checks/primary-scope.mjs +49 -0
- package/dist/guidance/references/build/checks/render-tells.mjs +72 -0
- package/dist/guidance/references/build/checks/screen-layout-pattern.mjs +111 -0
- package/dist/guidance/references/build/checks/semantics.mjs +72 -0
- package/dist/guidance/references/build/checks/settings-pattern.mjs +73 -0
- package/dist/guidance/references/build/checks/sync-pattern.mjs +62 -0
- package/dist/guidance/references/build/checks/tells-lint.mjs +164 -0
- package/dist/guidance/references/build/fixtures/pattern-workflows.tsx +83 -0
- package/dist/guidance/references/build/fixtures/patterns/agent-action.jsx +60 -0
- package/dist/guidance/references/build/fixtures/patterns/app-skeleton.jsx +94 -0
- package/dist/guidance/references/build/fixtures/patterns/assistant-conversation.jsx +79 -0
- package/dist/guidance/references/build/fixtures/patterns/audit-log.jsx +81 -0
- package/dist/guidance/references/build/fixtures/patterns/auth.jsx +150 -0
- package/dist/guidance/references/build/fixtures/patterns/billing.jsx +96 -0
- package/dist/guidance/references/build/fixtures/patterns/developer-settings.jsx +95 -0
- package/dist/guidance/references/build/fixtures/patterns/import.jsx +102 -0
- package/dist/guidance/references/build/fixtures/patterns/members.jsx +106 -0
- package/dist/guidance/references/build/fixtures/patterns/onboarding.jsx +70 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-decision.jsx +74 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-editor.jsx +56 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-report.jsx +42 -0
- package/dist/guidance/references/build/fixtures/patterns/settings.jsx +73 -0
- package/dist/guidance/references/build/fixtures/patterns/sync.jsx +78 -0
- package/dist/guidance/references/project/components/src/pattern-async-collection.tsx +57 -0
- package/dist/guidance/references/project/components/src/pattern-consequential-action.tsx +77 -0
- package/dist/guidance/references/project/components/src/pattern-edit-record.tsx +127 -0
- package/dist/guidance/references/project/components/src/pattern-review-submit.tsx +47 -0
- package/dist/guidance/references/project/components/src/settings.tsx +79 -0
- package/dist/guidance/references/scripts/build-framework-fixture.mjs +20 -0
- package/dist/guidance/rules.json +653 -0
- package/dist/guidance/visual/Elevation.md +194 -0
- package/dist/guidance/visual/Fundamentals.md +83 -0
- package/dist/guidance/visual/Research.md +1620 -0
- package/dist/index.cjs +19009 -1854
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +19009 -1854
- package/dist/index.js.map +4 -4
- package/dist/tokens.css +84 -84
- package/dist/tokens.json +301 -128
- package/dist/types/adapter-codemirror.d.ts +13 -0
- package/dist/types/agent-fleet.d.ts +166 -0
- package/dist/types/ai-label.d.ts +30 -0
- package/dist/types/app-shell.d.ts +83 -0
- package/dist/types/area-chart.d.ts +80 -0
- package/dist/types/artifact.d.ts +65 -0
- package/dist/types/bar-chart.d.ts +83 -0
- package/dist/types/bar-list.d.ts +35 -0
- package/dist/types/breadcrumb.d.ts +62 -0
- package/dist/types/chart-brush.d.ts +35 -0
- package/dist/types/chart-themes.d.ts +229 -0
- package/dist/types/chart.d.ts +570 -0
- package/dist/types/checklist.d.ts +71 -0
- package/dist/types/code-block.d.ts +32 -0
- package/dist/types/collections.d.ts +116 -5
- package/dist/types/color-picker.d.ts +38 -0
- package/dist/types/command.d.ts +6 -3
- package/dist/types/comment-thread.d.ts +48 -0
- package/dist/types/confirmation.d.ts +60 -0
- package/dist/types/context-menu.d.ts +17 -0
- package/dist/types/controls.d.ts +134 -22
- package/dist/types/conversation.d.ts +130 -0
- package/dist/types/copy-button.d.ts +19 -0
- package/dist/types/core.d.ts +139 -10
- package/dist/types/data-grid.d.ts +76 -0
- package/dist/types/date-picker.d.ts +96 -0
- package/dist/types/diff-view.d.ts +54 -0
- package/dist/types/dot-plot.d.ts +54 -0
- package/dist/types/edit-region.d.ts +121 -0
- package/dist/types/feature-gate.d.ts +22 -0
- package/dist/types/filter-bar.d.ts +65 -0
- package/dist/types/formatted-number.d.ts +38 -0
- package/dist/types/heatmap.d.ts +64 -0
- package/dist/types/in-place.d.ts +24 -0
- package/dist/types/index.d.ts +159 -14
- package/dist/types/inline-citation.d.ts +35 -0
- package/dist/types/inline-edit.d.ts +71 -0
- package/dist/types/input-otp.d.ts +37 -0
- package/dist/types/item-group.d.ts +104 -0
- package/dist/types/line-chart.d.ts +116 -0
- package/dist/types/link.d.ts +11 -0
- package/dist/types/markdown.d.ts +88 -0
- package/dist/types/meter.d.ts +43 -0
- package/dist/types/modal-state.d.ts +62 -0
- package/dist/types/nav.d.ts +8 -1
- package/dist/types/notifications.d.ts +42 -0
- package/dist/types/number-input.d.ts +30 -0
- package/dist/types/overlays.d.ts +56 -15
- package/dist/types/page-header.d.ts +27 -0
- package/dist/types/pagination.d.ts +29 -0
- package/dist/types/palette.d.ts +64 -0
- package/dist/types/password-input.d.ts +22 -0
- package/dist/types/pattern-assistant-conversation.d.ts +55 -0
- package/dist/types/pattern-async-collection.d.ts +34 -0
- package/dist/types/pattern-consequential-action.d.ts +53 -0
- package/dist/types/pattern-edit-record.d.ts +72 -0
- package/dist/types/pattern-review-submit.d.ts +43 -0
- package/dist/types/permission-matrix.d.ts +34 -0
- package/dist/types/plan-picker.d.ts +40 -0
- package/dist/types/prompt-input.d.ts +106 -0
- package/dist/types/property-list.d.ts +67 -0
- package/dist/types/question.d.ts +64 -0
- package/dist/types/relative-time.d.ts +21 -0
- package/dist/types/removal-receipt.d.ts +1180 -0
- package/dist/types/resizable.d.ts +48 -0
- package/dist/types/roving.d.ts +44 -0
- package/dist/types/save-bar.d.ts +38 -0
- package/dist/types/saved-views.d.ts +72 -0
- package/dist/types/scatter-chart.d.ts +60 -0
- package/dist/types/schedule.d.ts +80 -0
- package/dist/types/secret-field.d.ts +33 -0
- package/dist/types/select.d.ts +44 -2
- package/dist/types/separator.d.ts +11 -0
- package/dist/types/settings.d.ts +39 -0
- package/dist/types/sheet.d.ts +1 -1
- package/dist/types/sparkline.d.ts +46 -0
- package/dist/types/split-button.d.ts +21 -0
- package/dist/types/stat.d.ts +54 -0
- package/dist/types/stepper.d.ts +6 -3
- package/dist/types/suggestions.d.ts +29 -0
- package/dist/types/suspense.d.ts +85 -0
- package/dist/types/sync-indicator.d.ts +24 -0
- package/dist/types/tag-input.d.ts +65 -0
- package/dist/types/terminal.d.ts +33 -0
- package/dist/types/thread-list.d.ts +58 -0
- package/dist/types/time-input.d.ts +33 -0
- package/dist/types/timeline.d.ts +38 -0
- package/dist/types/toggle.d.ts +46 -0
- package/dist/types/toolbar.d.ts +34 -0
- package/dist/types/tour.d.ts +23 -0
- package/dist/types/trace.d.ts +65 -0
- package/dist/types/tree.d.ts +71 -0
- package/dist/types-cjs/adapter-codemirror.d.cts +13 -0
- package/dist/types-cjs/agent-fleet.d.cts +166 -0
- package/dist/types-cjs/ai-label.d.cts +30 -0
- package/dist/types-cjs/app-shell.d.cts +83 -0
- package/dist/types-cjs/area-chart.d.cts +80 -0
- package/dist/types-cjs/artifact.d.cts +65 -0
- package/dist/types-cjs/bar-chart.d.cts +83 -0
- package/dist/types-cjs/bar-list.d.cts +35 -0
- package/dist/types-cjs/breadcrumb.d.cts +62 -0
- package/dist/types-cjs/chart-brush.d.cts +35 -0
- package/dist/types-cjs/chart-themes.d.cts +229 -0
- package/dist/types-cjs/chart.d.cts +570 -0
- package/dist/types-cjs/checklist.d.cts +71 -0
- package/dist/types-cjs/code-block.d.cts +32 -0
- package/dist/types-cjs/collections.d.cts +246 -0
- package/dist/types-cjs/color-picker.d.cts +38 -0
- package/dist/types-cjs/command.d.cts +66 -0
- package/dist/types-cjs/comment-thread.d.cts +48 -0
- package/dist/types-cjs/confirmation.d.cts +60 -0
- package/dist/types-cjs/context-menu.d.cts +17 -0
- package/dist/types-cjs/controls.d.cts +360 -0
- package/dist/types-cjs/conversation.d.cts +130 -0
- package/dist/types-cjs/copy-button.d.cts +19 -0
- package/dist/types-cjs/core.d.cts +256 -0
- package/dist/types-cjs/data-grid.d.cts +76 -0
- package/dist/types-cjs/date-picker.d.cts +96 -0
- package/dist/types-cjs/diff-view.d.cts +54 -0
- package/dist/types-cjs/dot-plot.d.cts +54 -0
- package/dist/types-cjs/edit-region.d.cts +121 -0
- package/dist/types-cjs/empty.d.cts +24 -0
- package/dist/types-cjs/feature-gate.d.cts +22 -0
- package/dist/types-cjs/filter-bar.d.cts +65 -0
- package/dist/types-cjs/formatted-number.d.cts +38 -0
- package/dist/types-cjs/heatmap.d.cts +64 -0
- package/dist/types-cjs/in-place.d.cts +24 -0
- package/dist/types-cjs/index.d.cts +154 -0
- package/dist/types-cjs/inline-citation.d.cts +35 -0
- package/dist/types-cjs/inline-edit.d.cts +71 -0
- package/dist/types-cjs/input-otp.d.cts +37 -0
- package/dist/types-cjs/item-group.d.cts +104 -0
- package/dist/types-cjs/line-chart.d.cts +116 -0
- package/dist/types-cjs/link.d.cts +11 -0
- package/dist/types-cjs/markdown.d.cts +88 -0
- package/dist/types-cjs/meter.d.cts +43 -0
- package/dist/types-cjs/modal-state.d.cts +62 -0
- package/dist/types-cjs/nav.d.cts +25 -0
- package/dist/types-cjs/notifications.d.cts +42 -0
- package/dist/types-cjs/number-input.d.cts +30 -0
- package/dist/types-cjs/overlays.d.cts +170 -0
- package/dist/types-cjs/page-header.d.cts +27 -0
- package/dist/types-cjs/pagination.d.cts +29 -0
- package/dist/types-cjs/palette.d.cts +64 -0
- package/dist/types-cjs/password-input.d.cts +22 -0
- package/dist/types-cjs/pattern-assistant-conversation.d.cts +55 -0
- package/dist/types-cjs/pattern-async-collection.d.cts +34 -0
- package/dist/types-cjs/pattern-consequential-action.d.cts +53 -0
- package/dist/types-cjs/pattern-edit-record.d.cts +72 -0
- package/dist/types-cjs/pattern-review-submit.d.cts +43 -0
- package/dist/types-cjs/permission-matrix.d.cts +34 -0
- package/dist/types-cjs/pile.d.cts +27 -0
- package/dist/types-cjs/plan-picker.d.cts +40 -0
- package/dist/types-cjs/prompt-input.d.cts +106 -0
- package/dist/types-cjs/property-list.d.cts +67 -0
- package/dist/types-cjs/question.d.cts +64 -0
- package/dist/types-cjs/relative-time.d.cts +21 -0
- package/dist/types-cjs/removal-receipt.d.cts +1180 -0
- package/dist/types-cjs/resizable.d.cts +48 -0
- package/dist/types-cjs/roving.d.cts +44 -0
- package/dist/types-cjs/save-bar.d.cts +38 -0
- package/dist/types-cjs/saved-views.d.cts +72 -0
- package/dist/types-cjs/scatter-chart.d.cts +60 -0
- package/dist/types-cjs/schedule.d.cts +80 -0
- package/dist/types-cjs/secret-field.d.cts +33 -0
- package/dist/types-cjs/select.d.cts +109 -0
- package/dist/types-cjs/separator.d.cts +11 -0
- package/dist/types-cjs/settings.d.cts +39 -0
- package/dist/types-cjs/sheet.d.cts +27 -0
- package/dist/types-cjs/sparkline.d.cts +46 -0
- package/dist/types-cjs/split-button.d.cts +21 -0
- package/dist/types-cjs/stat.d.cts +54 -0
- package/dist/types-cjs/stepper.d.cts +26 -0
- package/dist/types-cjs/suggestions.d.cts +29 -0
- package/dist/types-cjs/suspense.d.cts +85 -0
- package/dist/types-cjs/sync-indicator.d.cts +24 -0
- package/dist/types-cjs/tag-input.d.cts +65 -0
- package/dist/types-cjs/terminal.d.cts +33 -0
- package/dist/types-cjs/thread-list.d.cts +58 -0
- package/dist/types-cjs/time-input.d.cts +33 -0
- package/dist/types-cjs/timeline.d.cts +38 -0
- package/dist/types-cjs/toggle.d.cts +46 -0
- package/dist/types-cjs/toolbar.d.cts +34 -0
- package/dist/types-cjs/tour.d.cts +23 -0
- package/dist/types-cjs/trace.d.cts +65 -0
- package/dist/types-cjs/tree.d.cts +71 -0
- package/package.json +90 -9
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// project/components/src/chart-themes.tsx
|
|
32
|
+
var chart_themes_exports = {};
|
|
33
|
+
__export(chart_themes_exports, {
|
|
34
|
+
chartjsDefaults: () => chartjsDefaults,
|
|
35
|
+
dataColors: () => dataColors,
|
|
36
|
+
echartsTheme: () => echartsTheme,
|
|
37
|
+
readChartTokens: () => readChartTokens,
|
|
38
|
+
useChartTheme: () => useChartTheme
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(chart_themes_exports);
|
|
41
|
+
var React = __toESM(require("react"), 1);
|
|
42
|
+
var READ = [
|
|
43
|
+
"data-1",
|
|
44
|
+
"data-2",
|
|
45
|
+
"data-3",
|
|
46
|
+
"data-4",
|
|
47
|
+
"data-5",
|
|
48
|
+
"data-6",
|
|
49
|
+
"data-other",
|
|
50
|
+
"data-seq-1",
|
|
51
|
+
"data-seq-2",
|
|
52
|
+
"data-seq-3",
|
|
53
|
+
"data-seq-4",
|
|
54
|
+
"data-seq-5",
|
|
55
|
+
"data-seq-6",
|
|
56
|
+
"data-seq-7",
|
|
57
|
+
"data-div-neg-3",
|
|
58
|
+
"data-div-neg-2",
|
|
59
|
+
"data-div-neg-1",
|
|
60
|
+
"data-div-mid",
|
|
61
|
+
"data-div-pos-1",
|
|
62
|
+
"data-div-pos-2",
|
|
63
|
+
"data-div-pos-3",
|
|
64
|
+
"surface-ground",
|
|
65
|
+
"surface-raised",
|
|
66
|
+
"surface-floating",
|
|
67
|
+
"ink",
|
|
68
|
+
"ink-muted",
|
|
69
|
+
"line",
|
|
70
|
+
"line-control",
|
|
71
|
+
"elev-3",
|
|
72
|
+
"font-sans",
|
|
73
|
+
"dur-travel-3"
|
|
74
|
+
];
|
|
75
|
+
var isElement = (s) => typeof s.getAttribute === "function";
|
|
76
|
+
function readChartTokens(source) {
|
|
77
|
+
if (!isElement(source)) return { ...source };
|
|
78
|
+
const cs = getComputedStyle(source);
|
|
79
|
+
return Object.fromEntries(READ.map((name) => [name, cs.getPropertyValue("--" + name).trim()]));
|
|
80
|
+
}
|
|
81
|
+
function resolveOptions(source, options) {
|
|
82
|
+
let { reducedMotion, forcedColors } = options;
|
|
83
|
+
if (isElement(source)) {
|
|
84
|
+
const win = source.ownerDocument.defaultView;
|
|
85
|
+
const travel = getComputedStyle(source).getPropertyValue("--alt-travel").trim();
|
|
86
|
+
reducedMotion ?? (reducedMotion = travel ? travel === "0" : !!win?.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
87
|
+
forcedColors ?? (forcedColors = !!win?.matchMedia("(forced-colors: active)").matches);
|
|
88
|
+
}
|
|
89
|
+
return { reducedMotion: !!reducedMotion, forcedColors: !!forcedColors, patterns: !!options.patterns || !!forcedColors };
|
|
90
|
+
}
|
|
91
|
+
var ms = (v, fallback) => {
|
|
92
|
+
const m = /^([\d.]+)(ms|s)$/.exec((v ?? "").trim());
|
|
93
|
+
return m ? Math.round(parseFloat(m[1]) * (m[2] === "s" ? 1e3 : 1)) : fallback;
|
|
94
|
+
};
|
|
95
|
+
var categorical = (t) => ["data-1", "data-2", "data-3", "data-4", "data-5", "data-6", "data-other"].map((n) => t[n]).filter(Boolean);
|
|
96
|
+
function dataColors(source) {
|
|
97
|
+
return categorical(readChartTokens(source));
|
|
98
|
+
}
|
|
99
|
+
function echartsTheme(source, options = {}) {
|
|
100
|
+
const t = readChartTokens(source);
|
|
101
|
+
const o = resolveOptions(source, options);
|
|
102
|
+
const duration = o.reducedMotion ? 0 : ms(t["dur-travel-3"], 220);
|
|
103
|
+
const text = { color: t["ink-muted"], fontFamily: t["font-sans"] };
|
|
104
|
+
const axis = {
|
|
105
|
+
axisLine: { lineStyle: { color: t["line-control"] } },
|
|
106
|
+
axisTick: { lineStyle: { color: t["line-control"] } },
|
|
107
|
+
axisLabel: { color: t["ink-muted"] },
|
|
108
|
+
splitLine: { lineStyle: { color: [t.line] } },
|
|
109
|
+
splitArea: { show: false }
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
color: categorical(t),
|
|
113
|
+
backgroundColor: "transparent",
|
|
114
|
+
textStyle: { color: t.ink, fontFamily: t["font-sans"] },
|
|
115
|
+
title: { textStyle: { color: t.ink }, subtextStyle: { color: t["ink-muted"] } },
|
|
116
|
+
legend: { textStyle: { color: t.ink }, inactiveColor: t["line-control"] },
|
|
117
|
+
categoryAxis: axis,
|
|
118
|
+
valueAxis: axis,
|
|
119
|
+
logAxis: axis,
|
|
120
|
+
timeAxis: axis,
|
|
121
|
+
tooltip: {
|
|
122
|
+
backgroundColor: t["surface-floating"],
|
|
123
|
+
borderColor: t.line,
|
|
124
|
+
borderWidth: 1,
|
|
125
|
+
textStyle: { color: t.ink, fontFamily: t["font-sans"] },
|
|
126
|
+
extraCssText: `box-shadow: ${t["elev-3"]}; border-radius: 8px;`,
|
|
127
|
+
axisPointer: { lineStyle: { color: t["line-control"], width: 1 }, crossStyle: { color: t["line-control"], width: 1 } }
|
|
128
|
+
},
|
|
129
|
+
// Magnitude reads the sequential ramp; set inRange to the diverging ramp for polarity.
|
|
130
|
+
visualMap: { inRange: { color: ["data-seq-1", "data-seq-2", "data-seq-3", "data-seq-4", "data-seq-5", "data-seq-6", "data-seq-7"].map((n) => t[n]) }, textStyle: text },
|
|
131
|
+
aria: { enabled: true, decal: { show: o.patterns } },
|
|
132
|
+
animation: !o.reducedMotion,
|
|
133
|
+
animationDuration: duration,
|
|
134
|
+
animationDurationUpdate: duration,
|
|
135
|
+
// ease-glide is cubic-bezier(0.65, 0, 0.35, 1): changed data glides at one level.
|
|
136
|
+
animationEasing: "cubicInOut",
|
|
137
|
+
animationEasingUpdate: "cubicInOut"
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function chartjsDefaults(source, options = {}) {
|
|
141
|
+
const t = readChartTokens(source);
|
|
142
|
+
const o = resolveOptions(source, options);
|
|
143
|
+
return {
|
|
144
|
+
color: t["ink-muted"],
|
|
145
|
+
borderColor: t.line,
|
|
146
|
+
backgroundColor: t["data-1"],
|
|
147
|
+
font: { family: t["font-sans"] },
|
|
148
|
+
animation: o.reducedMotion ? false : { duration: ms(t["dur-travel-3"], 220), easing: "easeInOutCubic" },
|
|
149
|
+
scale: { grid: { color: t.line }, border: { color: t["line-control"] }, ticks: { color: t["ink-muted"] } },
|
|
150
|
+
plugins: {
|
|
151
|
+
legend: { labels: { color: t.ink } },
|
|
152
|
+
tooltip: {
|
|
153
|
+
backgroundColor: t["surface-floating"],
|
|
154
|
+
borderColor: t.line,
|
|
155
|
+
borderWidth: 1,
|
|
156
|
+
titleColor: t.ink,
|
|
157
|
+
bodyColor: t.ink,
|
|
158
|
+
footerColor: t["ink-muted"]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function useChartTheme(build, ref, options) {
|
|
164
|
+
const [theme, setTheme] = React.useState(null);
|
|
165
|
+
const latest = React.useRef(build);
|
|
166
|
+
latest.current = build;
|
|
167
|
+
const key = JSON.stringify(options ?? {});
|
|
168
|
+
React.useEffect(() => {
|
|
169
|
+
const el = ref.current;
|
|
170
|
+
if (!el) return;
|
|
171
|
+
let last = "";
|
|
172
|
+
const read = () => {
|
|
173
|
+
const next = latest.current(el, options);
|
|
174
|
+
const id = JSON.stringify(next);
|
|
175
|
+
if (id !== last) {
|
|
176
|
+
last = id;
|
|
177
|
+
setTheme(next);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
read();
|
|
181
|
+
const mo = new MutationObserver(read);
|
|
182
|
+
for (let n = el; n; n = n.parentElement) {
|
|
183
|
+
mo.observe(n, { attributes: true, attributeFilter: ["data-theme", "data-motion", "data-contrast", "style", "class"] });
|
|
184
|
+
}
|
|
185
|
+
const win = el.ownerDocument.defaultView;
|
|
186
|
+
const queries = win ? ["(prefers-reduced-motion: reduce)", "(forced-colors: active)", "(prefers-color-scheme: dark)"].map((q) => win.matchMedia(q)) : [];
|
|
187
|
+
queries.forEach((q) => q.addEventListener("change", read));
|
|
188
|
+
return () => {
|
|
189
|
+
mo.disconnect();
|
|
190
|
+
queries.forEach((q) => q.removeEventListener("change", read));
|
|
191
|
+
};
|
|
192
|
+
}, [ref, key]);
|
|
193
|
+
return theme;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=chart-themes.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../project/components/src/chart-themes.tsx"],
|
|
4
|
+
"sourcesContent": ["// altitude-design/chart-themes: Altitude's palette, type, surfaces and motion as plain theme objects for canvas chart\n// libraries Altitude doesn't draw (ECharts, Chart.js). Nothing here imports either library, or the components: the\n// objects are read from the computed tokens of an element, or from tokens passed by name.\nimport * as React from 'react';\n\n/** Token values by name, without `--` (as in tokens.json), e.g. `{ 'data-1': '#3d5bd9', ink: '#141a29' }`. */\nexport type ChartTokens = Record<string, string>;\n/** An element to read the active scheme's computed tokens from, or the tokens themselves. */\nexport type ChartTokenSource = Element | ChartTokens;\n\nexport interface ChartThemeOptions {\n /** Zero every animation. Read from the element (`prefers-reduced-motion`, or `AltitudeProvider motion`) when omitted. */\n reducedMotion?: boolean;\n /** Turn on pattern fills (ECharts decals) so no series relies on colour alone. On under forced colours regardless. */\n patterns?: boolean;\n /** Forced colours are active. Read from the element's window when omitted. */\n forcedColors?: boolean;\n}\n\nconst READ = [\n 'data-1', 'data-2', 'data-3', 'data-4', 'data-5', 'data-6', 'data-other',\n 'data-seq-1', 'data-seq-2', 'data-seq-3', 'data-seq-4', 'data-seq-5', 'data-seq-6', 'data-seq-7',\n 'data-div-neg-3', 'data-div-neg-2', 'data-div-neg-1', 'data-div-mid', 'data-div-pos-1', 'data-div-pos-2', 'data-div-pos-3',\n 'surface-ground', 'surface-raised', 'surface-floating', 'ink', 'ink-muted', 'line', 'line-control',\n 'elev-3', 'font-sans', 'dur-travel-3',\n] as const;\n\nconst isElement = (s: ChartTokenSource): s is Element => typeof (s as Element).getAttribute === 'function';\n\n/** The tokens a chart theme needs, read from an element's computed style (so its scheme and accent apply). */\nexport function readChartTokens(source: ChartTokenSource): ChartTokens {\n if (!isElement(source)) return { ...source };\n const cs = getComputedStyle(source);\n return Object.fromEntries(READ.map((name) => [name, cs.getPropertyValue('--' + name).trim()]));\n}\n\nfunction resolveOptions(source: ChartTokenSource, options: ChartThemeOptions) {\n let { reducedMotion, forcedColors } = options;\n if (isElement(source)) {\n const win = source.ownerDocument.defaultView;\n // AltitudeProvider folds its motion prop and the system setting into --alt-travel (0 is reduced).\n const travel = getComputedStyle(source).getPropertyValue('--alt-travel').trim();\n reducedMotion ??= travel ? travel === '0' : !!win?.matchMedia('(prefers-reduced-motion: reduce)').matches;\n forcedColors ??= !!win?.matchMedia('(forced-colors: active)').matches;\n }\n return { reducedMotion: !!reducedMotion, forcedColors: !!forcedColors, patterns: !!options.patterns || !!forcedColors };\n}\n\nconst ms = (v: string | undefined, fallback: number) => {\n const m = /^([\\d.]+)(ms|s)$/.exec((v ?? '').trim());\n return m ? Math.round(parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1)) : fallback;\n};\n\nconst categorical = (t: ChartTokens) => ['data-1', 'data-2', 'data-3', 'data-4', 'data-5', 'data-6', 'data-other'].map((n) => t[n]).filter(Boolean);\n\n/** data-1 \u2026 data-6, then data-other: series colours in config order, for a library that takes a list. */\nexport function dataColors(source: ChartTokenSource): string[] {\n return categorical(readChartTokens(source));\n}\n\n/**\n * An ECharts theme: `echarts.init(el, echartsTheme(el))`, or `echarts.registerTheme('altitude', echartsTheme(el))`.\n * Series in data-1 \u2026 data-6 then data-other, text in ink, axes in line-control, split lines in line, the readout on\n * surface-floating at elev-3, aria on (import ECharts' AriaComponent), decals under forced colours or with `patterns`,\n * and dur-travel-3 animation on ease-glide's curve, zero under reduced motion.\n */\nexport function echartsTheme(source: ChartTokenSource, options: ChartThemeOptions = {}) {\n const t = readChartTokens(source);\n const o = resolveOptions(source, options);\n const duration = o.reducedMotion ? 0 : ms(t['dur-travel-3'], 220);\n const text = { color: t['ink-muted'], fontFamily: t['font-sans'] };\n const axis = {\n axisLine: { lineStyle: { color: t['line-control'] } },\n axisTick: { lineStyle: { color: t['line-control'] } },\n axisLabel: { color: t['ink-muted'] },\n splitLine: { lineStyle: { color: [t.line] } },\n splitArea: { show: false },\n };\n return {\n color: categorical(t),\n backgroundColor: 'transparent',\n textStyle: { color: t.ink, fontFamily: t['font-sans'] },\n title: { textStyle: { color: t.ink }, subtextStyle: { color: t['ink-muted'] } },\n legend: { textStyle: { color: t.ink }, inactiveColor: t['line-control'] },\n categoryAxis: axis, valueAxis: axis, logAxis: axis, timeAxis: axis,\n tooltip: {\n backgroundColor: t['surface-floating'], borderColor: t.line, borderWidth: 1,\n textStyle: { color: t.ink, fontFamily: t['font-sans'] },\n extraCssText: `box-shadow: ${t['elev-3']}; border-radius: 8px;`,\n axisPointer: { lineStyle: { color: t['line-control'], width: 1 }, crossStyle: { color: t['line-control'], width: 1 } },\n },\n // Magnitude reads the sequential ramp; set inRange to the diverging ramp for polarity.\n visualMap: { inRange: { color: ['data-seq-1', 'data-seq-2', 'data-seq-3', 'data-seq-4', 'data-seq-5', 'data-seq-6', 'data-seq-7'].map((n) => t[n]) }, textStyle: text },\n aria: { enabled: true, decal: { show: o.patterns } },\n animation: !o.reducedMotion,\n animationDuration: duration,\n animationDurationUpdate: duration,\n // ease-glide is cubic-bezier(0.65, 0, 0.35, 1): changed data glides at one level.\n animationEasing: 'cubicInOut', animationEasingUpdate: 'cubicInOut',\n };\n}\n\n/**\n * Chart.js defaults: `Chart.defaults.set(chartjsDefaults(el))`. Text in ink-muted, grid in line, axis borders in\n * line-control, the readout on surface-floating, dur-travel-3 animation (none under reduced motion). Chart.js has no\n * palette default: give each dataset a colour from `dataColors(el)`.\n */\nexport function chartjsDefaults(source: ChartTokenSource, options: ChartThemeOptions = {}) {\n const t = readChartTokens(source);\n const o = resolveOptions(source, options);\n return {\n color: t['ink-muted'],\n borderColor: t.line,\n backgroundColor: t['data-1'],\n font: { family: t['font-sans'] },\n animation: o.reducedMotion ? false as const : { duration: ms(t['dur-travel-3'], 220), easing: 'easeInOutCubic' as const },\n scale: { grid: { color: t.line }, border: { color: t['line-control'] }, ticks: { color: t['ink-muted'] } },\n plugins: {\n legend: { labels: { color: t.ink } },\n tooltip: {\n backgroundColor: t['surface-floating'], borderColor: t.line, borderWidth: 1,\n titleColor: t.ink, bodyColor: t.ink, footerColor: t['ink-muted'],\n },\n },\n };\n}\n\n/**\n * Re-reads a chart theme whenever the scheme around `ref` changes: an AltitudeProvider's `scheme`, `accent` or\n * `motion`, a `data-theme` on the page, or the reduced-motion and forced-colours settings. Null until mounted.\n *\n * const ref = React.useRef<HTMLDivElement>(null);\n * const theme = useChartTheme(echartsTheme, ref);\n * React.useEffect(() => { if (!theme) return; const c = echarts.init(ref.current!, theme); \u2026; return () => c.dispose(); }, [theme]);\n */\nexport function useChartTheme<T>(build: (source: Element, options?: ChartThemeOptions) => T, ref: React.RefObject<Element | null>, options?: ChartThemeOptions): T | null {\n const [theme, setTheme] = React.useState<T | null>(null);\n const latest = React.useRef(build);\n latest.current = build;\n const key = JSON.stringify(options ?? {});\n React.useEffect(() => {\n const el = ref.current;\n if (!el) return;\n let last = '';\n const read = () => {\n const next = latest.current(el, options);\n const id = JSON.stringify(next);\n if (id !== last) { last = id; setTheme(next); }\n };\n read();\n const mo = new MutationObserver(read);\n // Every ancestor that can carry a scheme: the provider's root sets data-theme, its accent as inline style.\n for (let n: Element | null = el; n; n = n.parentElement) {\n mo.observe(n, { attributes: true, attributeFilter: ['data-theme', 'data-motion', 'data-contrast', 'style', 'class'] });\n }\n const win = el.ownerDocument.defaultView;\n const queries = win ? ['(prefers-reduced-motion: reduce)', '(forced-colors: active)', '(prefers-color-scheme: dark)'].map((q) => win.matchMedia(q)) : [];\n queries.forEach((q) => q.addEventListener('change', read));\n return () => { mo.disconnect(); queries.forEach((q) => q.removeEventListener('change', read)); };\n }, [ref, key]); // eslint-disable-line react-hooks/exhaustive-deps\n return theme;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// project/components/src/chart-themes.tsx
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
var READ = [
|
|
6
|
+
"data-1",
|
|
7
|
+
"data-2",
|
|
8
|
+
"data-3",
|
|
9
|
+
"data-4",
|
|
10
|
+
"data-5",
|
|
11
|
+
"data-6",
|
|
12
|
+
"data-other",
|
|
13
|
+
"data-seq-1",
|
|
14
|
+
"data-seq-2",
|
|
15
|
+
"data-seq-3",
|
|
16
|
+
"data-seq-4",
|
|
17
|
+
"data-seq-5",
|
|
18
|
+
"data-seq-6",
|
|
19
|
+
"data-seq-7",
|
|
20
|
+
"data-div-neg-3",
|
|
21
|
+
"data-div-neg-2",
|
|
22
|
+
"data-div-neg-1",
|
|
23
|
+
"data-div-mid",
|
|
24
|
+
"data-div-pos-1",
|
|
25
|
+
"data-div-pos-2",
|
|
26
|
+
"data-div-pos-3",
|
|
27
|
+
"surface-ground",
|
|
28
|
+
"surface-raised",
|
|
29
|
+
"surface-floating",
|
|
30
|
+
"ink",
|
|
31
|
+
"ink-muted",
|
|
32
|
+
"line",
|
|
33
|
+
"line-control",
|
|
34
|
+
"elev-3",
|
|
35
|
+
"font-sans",
|
|
36
|
+
"dur-travel-3"
|
|
37
|
+
];
|
|
38
|
+
var isElement = (s) => typeof s.getAttribute === "function";
|
|
39
|
+
function readChartTokens(source) {
|
|
40
|
+
if (!isElement(source)) return { ...source };
|
|
41
|
+
const cs = getComputedStyle(source);
|
|
42
|
+
return Object.fromEntries(READ.map((name) => [name, cs.getPropertyValue("--" + name).trim()]));
|
|
43
|
+
}
|
|
44
|
+
function resolveOptions(source, options) {
|
|
45
|
+
let { reducedMotion, forcedColors } = options;
|
|
46
|
+
if (isElement(source)) {
|
|
47
|
+
const win = source.ownerDocument.defaultView;
|
|
48
|
+
const travel = getComputedStyle(source).getPropertyValue("--alt-travel").trim();
|
|
49
|
+
reducedMotion ?? (reducedMotion = travel ? travel === "0" : !!win?.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
50
|
+
forcedColors ?? (forcedColors = !!win?.matchMedia("(forced-colors: active)").matches);
|
|
51
|
+
}
|
|
52
|
+
return { reducedMotion: !!reducedMotion, forcedColors: !!forcedColors, patterns: !!options.patterns || !!forcedColors };
|
|
53
|
+
}
|
|
54
|
+
var ms = (v, fallback) => {
|
|
55
|
+
const m = /^([\d.]+)(ms|s)$/.exec((v ?? "").trim());
|
|
56
|
+
return m ? Math.round(parseFloat(m[1]) * (m[2] === "s" ? 1e3 : 1)) : fallback;
|
|
57
|
+
};
|
|
58
|
+
var categorical = (t) => ["data-1", "data-2", "data-3", "data-4", "data-5", "data-6", "data-other"].map((n) => t[n]).filter(Boolean);
|
|
59
|
+
function dataColors(source) {
|
|
60
|
+
return categorical(readChartTokens(source));
|
|
61
|
+
}
|
|
62
|
+
function echartsTheme(source, options = {}) {
|
|
63
|
+
const t = readChartTokens(source);
|
|
64
|
+
const o = resolveOptions(source, options);
|
|
65
|
+
const duration = o.reducedMotion ? 0 : ms(t["dur-travel-3"], 220);
|
|
66
|
+
const text = { color: t["ink-muted"], fontFamily: t["font-sans"] };
|
|
67
|
+
const axis = {
|
|
68
|
+
axisLine: { lineStyle: { color: t["line-control"] } },
|
|
69
|
+
axisTick: { lineStyle: { color: t["line-control"] } },
|
|
70
|
+
axisLabel: { color: t["ink-muted"] },
|
|
71
|
+
splitLine: { lineStyle: { color: [t.line] } },
|
|
72
|
+
splitArea: { show: false }
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
color: categorical(t),
|
|
76
|
+
backgroundColor: "transparent",
|
|
77
|
+
textStyle: { color: t.ink, fontFamily: t["font-sans"] },
|
|
78
|
+
title: { textStyle: { color: t.ink }, subtextStyle: { color: t["ink-muted"] } },
|
|
79
|
+
legend: { textStyle: { color: t.ink }, inactiveColor: t["line-control"] },
|
|
80
|
+
categoryAxis: axis,
|
|
81
|
+
valueAxis: axis,
|
|
82
|
+
logAxis: axis,
|
|
83
|
+
timeAxis: axis,
|
|
84
|
+
tooltip: {
|
|
85
|
+
backgroundColor: t["surface-floating"],
|
|
86
|
+
borderColor: t.line,
|
|
87
|
+
borderWidth: 1,
|
|
88
|
+
textStyle: { color: t.ink, fontFamily: t["font-sans"] },
|
|
89
|
+
extraCssText: `box-shadow: ${t["elev-3"]}; border-radius: 8px;`,
|
|
90
|
+
axisPointer: { lineStyle: { color: t["line-control"], width: 1 }, crossStyle: { color: t["line-control"], width: 1 } }
|
|
91
|
+
},
|
|
92
|
+
// Magnitude reads the sequential ramp; set inRange to the diverging ramp for polarity.
|
|
93
|
+
visualMap: { inRange: { color: ["data-seq-1", "data-seq-2", "data-seq-3", "data-seq-4", "data-seq-5", "data-seq-6", "data-seq-7"].map((n) => t[n]) }, textStyle: text },
|
|
94
|
+
aria: { enabled: true, decal: { show: o.patterns } },
|
|
95
|
+
animation: !o.reducedMotion,
|
|
96
|
+
animationDuration: duration,
|
|
97
|
+
animationDurationUpdate: duration,
|
|
98
|
+
// ease-glide is cubic-bezier(0.65, 0, 0.35, 1): changed data glides at one level.
|
|
99
|
+
animationEasing: "cubicInOut",
|
|
100
|
+
animationEasingUpdate: "cubicInOut"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function chartjsDefaults(source, options = {}) {
|
|
104
|
+
const t = readChartTokens(source);
|
|
105
|
+
const o = resolveOptions(source, options);
|
|
106
|
+
return {
|
|
107
|
+
color: t["ink-muted"],
|
|
108
|
+
borderColor: t.line,
|
|
109
|
+
backgroundColor: t["data-1"],
|
|
110
|
+
font: { family: t["font-sans"] },
|
|
111
|
+
animation: o.reducedMotion ? false : { duration: ms(t["dur-travel-3"], 220), easing: "easeInOutCubic" },
|
|
112
|
+
scale: { grid: { color: t.line }, border: { color: t["line-control"] }, ticks: { color: t["ink-muted"] } },
|
|
113
|
+
plugins: {
|
|
114
|
+
legend: { labels: { color: t.ink } },
|
|
115
|
+
tooltip: {
|
|
116
|
+
backgroundColor: t["surface-floating"],
|
|
117
|
+
borderColor: t.line,
|
|
118
|
+
borderWidth: 1,
|
|
119
|
+
titleColor: t.ink,
|
|
120
|
+
bodyColor: t.ink,
|
|
121
|
+
footerColor: t["ink-muted"]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function useChartTheme(build, ref, options) {
|
|
127
|
+
const [theme, setTheme] = React.useState(null);
|
|
128
|
+
const latest = React.useRef(build);
|
|
129
|
+
latest.current = build;
|
|
130
|
+
const key = JSON.stringify(options ?? {});
|
|
131
|
+
React.useEffect(() => {
|
|
132
|
+
const el = ref.current;
|
|
133
|
+
if (!el) return;
|
|
134
|
+
let last = "";
|
|
135
|
+
const read = () => {
|
|
136
|
+
const next = latest.current(el, options);
|
|
137
|
+
const id = JSON.stringify(next);
|
|
138
|
+
if (id !== last) {
|
|
139
|
+
last = id;
|
|
140
|
+
setTheme(next);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
read();
|
|
144
|
+
const mo = new MutationObserver(read);
|
|
145
|
+
for (let n = el; n; n = n.parentElement) {
|
|
146
|
+
mo.observe(n, { attributes: true, attributeFilter: ["data-theme", "data-motion", "data-contrast", "style", "class"] });
|
|
147
|
+
}
|
|
148
|
+
const win = el.ownerDocument.defaultView;
|
|
149
|
+
const queries = win ? ["(prefers-reduced-motion: reduce)", "(forced-colors: active)", "(prefers-color-scheme: dark)"].map((q) => win.matchMedia(q)) : [];
|
|
150
|
+
queries.forEach((q) => q.addEventListener("change", read));
|
|
151
|
+
return () => {
|
|
152
|
+
mo.disconnect();
|
|
153
|
+
queries.forEach((q) => q.removeEventListener("change", read));
|
|
154
|
+
};
|
|
155
|
+
}, [ref, key]);
|
|
156
|
+
return theme;
|
|
157
|
+
}
|
|
158
|
+
export {
|
|
159
|
+
chartjsDefaults,
|
|
160
|
+
dataColors,
|
|
161
|
+
echartsTheme,
|
|
162
|
+
readChartTokens,
|
|
163
|
+
useChartTheme
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=chart-themes.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../project/components/src/chart-themes.tsx"],
|
|
4
|
+
"sourcesContent": ["// altitude-design/chart-themes: Altitude's palette, type, surfaces and motion as plain theme objects for canvas chart\n// libraries Altitude doesn't draw (ECharts, Chart.js). Nothing here imports either library, or the components: the\n// objects are read from the computed tokens of an element, or from tokens passed by name.\nimport * as React from 'react';\n\n/** Token values by name, without `--` (as in tokens.json), e.g. `{ 'data-1': '#3d5bd9', ink: '#141a29' }`. */\nexport type ChartTokens = Record<string, string>;\n/** An element to read the active scheme's computed tokens from, or the tokens themselves. */\nexport type ChartTokenSource = Element | ChartTokens;\n\nexport interface ChartThemeOptions {\n /** Zero every animation. Read from the element (`prefers-reduced-motion`, or `AltitudeProvider motion`) when omitted. */\n reducedMotion?: boolean;\n /** Turn on pattern fills (ECharts decals) so no series relies on colour alone. On under forced colours regardless. */\n patterns?: boolean;\n /** Forced colours are active. Read from the element's window when omitted. */\n forcedColors?: boolean;\n}\n\nconst READ = [\n 'data-1', 'data-2', 'data-3', 'data-4', 'data-5', 'data-6', 'data-other',\n 'data-seq-1', 'data-seq-2', 'data-seq-3', 'data-seq-4', 'data-seq-5', 'data-seq-6', 'data-seq-7',\n 'data-div-neg-3', 'data-div-neg-2', 'data-div-neg-1', 'data-div-mid', 'data-div-pos-1', 'data-div-pos-2', 'data-div-pos-3',\n 'surface-ground', 'surface-raised', 'surface-floating', 'ink', 'ink-muted', 'line', 'line-control',\n 'elev-3', 'font-sans', 'dur-travel-3',\n] as const;\n\nconst isElement = (s: ChartTokenSource): s is Element => typeof (s as Element).getAttribute === 'function';\n\n/** The tokens a chart theme needs, read from an element's computed style (so its scheme and accent apply). */\nexport function readChartTokens(source: ChartTokenSource): ChartTokens {\n if (!isElement(source)) return { ...source };\n const cs = getComputedStyle(source);\n return Object.fromEntries(READ.map((name) => [name, cs.getPropertyValue('--' + name).trim()]));\n}\n\nfunction resolveOptions(source: ChartTokenSource, options: ChartThemeOptions) {\n let { reducedMotion, forcedColors } = options;\n if (isElement(source)) {\n const win = source.ownerDocument.defaultView;\n // AltitudeProvider folds its motion prop and the system setting into --alt-travel (0 is reduced).\n const travel = getComputedStyle(source).getPropertyValue('--alt-travel').trim();\n reducedMotion ??= travel ? travel === '0' : !!win?.matchMedia('(prefers-reduced-motion: reduce)').matches;\n forcedColors ??= !!win?.matchMedia('(forced-colors: active)').matches;\n }\n return { reducedMotion: !!reducedMotion, forcedColors: !!forcedColors, patterns: !!options.patterns || !!forcedColors };\n}\n\nconst ms = (v: string | undefined, fallback: number) => {\n const m = /^([\\d.]+)(ms|s)$/.exec((v ?? '').trim());\n return m ? Math.round(parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1)) : fallback;\n};\n\nconst categorical = (t: ChartTokens) => ['data-1', 'data-2', 'data-3', 'data-4', 'data-5', 'data-6', 'data-other'].map((n) => t[n]).filter(Boolean);\n\n/** data-1 \u2026 data-6, then data-other: series colours in config order, for a library that takes a list. */\nexport function dataColors(source: ChartTokenSource): string[] {\n return categorical(readChartTokens(source));\n}\n\n/**\n * An ECharts theme: `echarts.init(el, echartsTheme(el))`, or `echarts.registerTheme('altitude', echartsTheme(el))`.\n * Series in data-1 \u2026 data-6 then data-other, text in ink, axes in line-control, split lines in line, the readout on\n * surface-floating at elev-3, aria on (import ECharts' AriaComponent), decals under forced colours or with `patterns`,\n * and dur-travel-3 animation on ease-glide's curve, zero under reduced motion.\n */\nexport function echartsTheme(source: ChartTokenSource, options: ChartThemeOptions = {}) {\n const t = readChartTokens(source);\n const o = resolveOptions(source, options);\n const duration = o.reducedMotion ? 0 : ms(t['dur-travel-3'], 220);\n const text = { color: t['ink-muted'], fontFamily: t['font-sans'] };\n const axis = {\n axisLine: { lineStyle: { color: t['line-control'] } },\n axisTick: { lineStyle: { color: t['line-control'] } },\n axisLabel: { color: t['ink-muted'] },\n splitLine: { lineStyle: { color: [t.line] } },\n splitArea: { show: false },\n };\n return {\n color: categorical(t),\n backgroundColor: 'transparent',\n textStyle: { color: t.ink, fontFamily: t['font-sans'] },\n title: { textStyle: { color: t.ink }, subtextStyle: { color: t['ink-muted'] } },\n legend: { textStyle: { color: t.ink }, inactiveColor: t['line-control'] },\n categoryAxis: axis, valueAxis: axis, logAxis: axis, timeAxis: axis,\n tooltip: {\n backgroundColor: t['surface-floating'], borderColor: t.line, borderWidth: 1,\n textStyle: { color: t.ink, fontFamily: t['font-sans'] },\n extraCssText: `box-shadow: ${t['elev-3']}; border-radius: 8px;`,\n axisPointer: { lineStyle: { color: t['line-control'], width: 1 }, crossStyle: { color: t['line-control'], width: 1 } },\n },\n // Magnitude reads the sequential ramp; set inRange to the diverging ramp for polarity.\n visualMap: { inRange: { color: ['data-seq-1', 'data-seq-2', 'data-seq-3', 'data-seq-4', 'data-seq-5', 'data-seq-6', 'data-seq-7'].map((n) => t[n]) }, textStyle: text },\n aria: { enabled: true, decal: { show: o.patterns } },\n animation: !o.reducedMotion,\n animationDuration: duration,\n animationDurationUpdate: duration,\n // ease-glide is cubic-bezier(0.65, 0, 0.35, 1): changed data glides at one level.\n animationEasing: 'cubicInOut', animationEasingUpdate: 'cubicInOut',\n };\n}\n\n/**\n * Chart.js defaults: `Chart.defaults.set(chartjsDefaults(el))`. Text in ink-muted, grid in line, axis borders in\n * line-control, the readout on surface-floating, dur-travel-3 animation (none under reduced motion). Chart.js has no\n * palette default: give each dataset a colour from `dataColors(el)`.\n */\nexport function chartjsDefaults(source: ChartTokenSource, options: ChartThemeOptions = {}) {\n const t = readChartTokens(source);\n const o = resolveOptions(source, options);\n return {\n color: t['ink-muted'],\n borderColor: t.line,\n backgroundColor: t['data-1'],\n font: { family: t['font-sans'] },\n animation: o.reducedMotion ? false as const : { duration: ms(t['dur-travel-3'], 220), easing: 'easeInOutCubic' as const },\n scale: { grid: { color: t.line }, border: { color: t['line-control'] }, ticks: { color: t['ink-muted'] } },\n plugins: {\n legend: { labels: { color: t.ink } },\n tooltip: {\n backgroundColor: t['surface-floating'], borderColor: t.line, borderWidth: 1,\n titleColor: t.ink, bodyColor: t.ink, footerColor: t['ink-muted'],\n },\n },\n };\n}\n\n/**\n * Re-reads a chart theme whenever the scheme around `ref` changes: an AltitudeProvider's `scheme`, `accent` or\n * `motion`, a `data-theme` on the page, or the reduced-motion and forced-colours settings. Null until mounted.\n *\n * const ref = React.useRef<HTMLDivElement>(null);\n * const theme = useChartTheme(echartsTheme, ref);\n * React.useEffect(() => { if (!theme) return; const c = echarts.init(ref.current!, theme); \u2026; return () => c.dispose(); }, [theme]);\n */\nexport function useChartTheme<T>(build: (source: Element, options?: ChartThemeOptions) => T, ref: React.RefObject<Element | null>, options?: ChartThemeOptions): T | null {\n const [theme, setTheme] = React.useState<T | null>(null);\n const latest = React.useRef(build);\n latest.current = build;\n const key = JSON.stringify(options ?? {});\n React.useEffect(() => {\n const el = ref.current;\n if (!el) return;\n let last = '';\n const read = () => {\n const next = latest.current(el, options);\n const id = JSON.stringify(next);\n if (id !== last) { last = id; setTheme(next); }\n };\n read();\n const mo = new MutationObserver(read);\n // Every ancestor that can carry a scheme: the provider's root sets data-theme, its accent as inline style.\n for (let n: Element | null = el; n; n = n.parentElement) {\n mo.observe(n, { attributes: true, attributeFilter: ['data-theme', 'data-motion', 'data-contrast', 'style', 'class'] });\n }\n const win = el.ownerDocument.defaultView;\n const queries = win ? ['(prefers-reduced-motion: reduce)', '(forced-colors: active)', '(prefers-color-scheme: dark)'].map((q) => win.matchMedia(q)) : [];\n queries.forEach((q) => q.addEventListener('change', read));\n return () => { mo.disconnect(); queries.forEach((q) => q.removeEventListener('change', read)); };\n }, [ref, key]); // eslint-disable-line react-hooks/exhaustive-deps\n return theme;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// scripts/altitude-cli.mjs
|
|
4
|
+
import { existsSync, lstatSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { resolve, dirname, relative, basename } from "node:path";
|
|
8
|
+
var sha = (value2) => createHash("sha256").update(value2).digest("hex");
|
|
9
|
+
var args = process.argv.slice(2);
|
|
10
|
+
var command = args.shift() || "help";
|
|
11
|
+
var value = (name) => {
|
|
12
|
+
const i = args.indexOf(name);
|
|
13
|
+
return i < 0 ? void 0 : args[i + 1];
|
|
14
|
+
};
|
|
15
|
+
var cwd = resolve(value("--cwd") || process.cwd());
|
|
16
|
+
var json = args.includes("--json");
|
|
17
|
+
var emit = (result) => console.log(JSON.stringify(result, null, 2));
|
|
18
|
+
function installed() {
|
|
19
|
+
const path = createRequire(resolve(cwd, "package.json")).resolve("altitude-design/package.json");
|
|
20
|
+
const pkg = JSON.parse(readFileSync(path, "utf8"));
|
|
21
|
+
const guidance = resolve(dirname(path), "dist/guidance");
|
|
22
|
+
const index = JSON.parse(readFileSync(resolve(guidance, "index.json"), "utf8"));
|
|
23
|
+
return { pkg, guidance, index };
|
|
24
|
+
}
|
|
25
|
+
function managed(text) {
|
|
26
|
+
const starts = [...text.matchAll(/<!-- altitude:start/g)], ends = [...text.matchAll(/<!-- altitude:end -->/g)];
|
|
27
|
+
if (!starts.length && !ends.length) return null;
|
|
28
|
+
if (starts.length !== 1 || ends.length !== 1) throw new Error("Malformed or duplicate Altitude markers; reconcile them manually.");
|
|
29
|
+
const re = /\n<!-- altitude:start created=(true|false) hash=([a-f0-9]{64}) -->\n([\s\S]*?)<!-- altitude:end -->\n/;
|
|
30
|
+
const m = re.exec(text);
|
|
31
|
+
if (!m || sha(m[3]) !== m[2]) throw new Error("The managed Altitude block was edited; preserve your edits and reconcile it manually.");
|
|
32
|
+
return { start: m.index, end: m.index + m[0].length, created: m[1] === "true", body: m[3] };
|
|
33
|
+
}
|
|
34
|
+
function block(version, guidance, created) {
|
|
35
|
+
const path = relative(cwd, guidance).replaceAll("\\", "/");
|
|
36
|
+
const body = `## Altitude framework (${version})
|
|
37
|
+
For UI tasks using altitude-design, first read ${path}/README.md, then only the matching pattern document.
|
|
38
|
+
Discover tasks with npm exec -- altitude patterns "your intent"; explain a rule with npm exec -- altitude explain RULE-ID.
|
|
39
|
+
Use the installed public declarations and examples. Record applicable states and application-owned persistence, permissions and navigation.
|
|
40
|
+
Run the pattern checks and application service fixtures; distinguish deterministic defects, integration obligations and contextual review.
|
|
41
|
+
Use npm exec -- altitude doctor --json after package upgrades, and rerun npm exec -- altitude init to refresh this versioned pointer.
|
|
42
|
+
`;
|
|
43
|
+
return `
|
|
44
|
+
<!-- altitude:start created=${created} hash=${sha(body)} -->
|
|
45
|
+
${body}<!-- altitude:end -->
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function instructionPath(client) {
|
|
49
|
+
const override = resolve(cwd, "AGENTS.override.md");
|
|
50
|
+
if (client === "codex" && existsSync(override) && readFileSync(override, "utf8").trim()) return override;
|
|
51
|
+
return resolve(cwd, client === "codex" ? "AGENTS.md" : "CLAUDE.md");
|
|
52
|
+
}
|
|
53
|
+
function isSymlink(path) {
|
|
54
|
+
try {
|
|
55
|
+
return lstatSync(path).isSymbolicLink();
|
|
56
|
+
} catch (e) {
|
|
57
|
+
if (e.code === "ENOENT") return false;
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function init(context) {
|
|
62
|
+
if (context.pkg.version !== context.index.version) throw new Error("Installed package and guidance versions differ; reinstall before setup.");
|
|
63
|
+
const client = value("--client");
|
|
64
|
+
const clients = client === "all" ? ["codex", "claude"] : [client];
|
|
65
|
+
if (clients.some((c) => !["codex", "claude"].includes(c))) throw new Error("Choose --client codex, claude, or all.");
|
|
66
|
+
const remove = args.includes("--remove");
|
|
67
|
+
const targets = clients.flatMap((client2) => (remove && client2 === "codex" ? [resolve(cwd, "AGENTS.md"), resolve(cwd, "AGENTS.override.md")] : [instructionPath(client2)]).map((path) => ({ client: client2, path })));
|
|
68
|
+
const changes = targets.map(({ client: c, path }) => {
|
|
69
|
+
if (isSymlink(path)) throw new Error(`Refusing instruction symlink: ${path}`);
|
|
70
|
+
const existed = existsSync(path), before = existed ? readFileSync(path, "utf8") : "";
|
|
71
|
+
const old = managed(before);
|
|
72
|
+
const replacement = remove ? "" : block(context.pkg.version, context.guidance, old?.created ?? !existed);
|
|
73
|
+
const after = old ? before.slice(0, old.start) + replacement + before.slice(old.end) : before + (remove ? "" : replacement);
|
|
74
|
+
const deleteFile = remove && old?.created && after === "";
|
|
75
|
+
return { client: c, path, before, after, action: deleteFile ? "delete" : before === after ? "unchanged" : existed ? "update" : "create" };
|
|
76
|
+
});
|
|
77
|
+
emit({ command: "init", mode: args.includes("--apply") ? "apply" : "preview", version: context.pkg.version, changes });
|
|
78
|
+
if (args.includes("--apply")) for (const c of changes) {
|
|
79
|
+
if (c.action === "delete") unlinkSync(c.path);
|
|
80
|
+
else if (c.action !== "unchanged") writeFileSync(c.path, c.after);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function finding(ruleId, kind, status, observed, expected, repair, verification) {
|
|
84
|
+
return { ruleId, kind, status, observed, expected, repair, verification };
|
|
85
|
+
}
|
|
86
|
+
function doctor(context) {
|
|
87
|
+
const findings = [];
|
|
88
|
+
if (context.pkg.version !== context.index.version) findings.push(finding("ALT-SETUP-001", "deterministic", "fail", `Package ${context.pkg.version}; guidance ${context.index.version}`, "Matching versions", "Reinstall a coherent package.", "altitude doctor --json"));
|
|
89
|
+
const manifest = JSON.parse(readFileSync(resolve(context.guidance, "manifest.json"), "utf8"));
|
|
90
|
+
if (manifest.version !== context.pkg.version) findings.push(finding("ALT-SETUP-001", "deterministic", "fail", `Manifest ${manifest.version}`, "Manifest matches installed package", "Reinstall the package.", "altitude doctor --json"));
|
|
91
|
+
for (const [file, digest] of Object.entries(manifest.files)) {
|
|
92
|
+
const path = resolve(context.guidance, file);
|
|
93
|
+
if (!path.startsWith(context.guidance + "/") || !existsSync(path) || sha(readFileSync(path)) !== digest) findings.push(finding("ALT-SETUP-001", "deterministic", "fail", `Missing or modified guidance: ${file}`, "Unmodified version-matched guidance", "Reinstall the package.", "altitude doctor --json"));
|
|
94
|
+
}
|
|
95
|
+
for (const client of ["codex", "claude"]) {
|
|
96
|
+
const path = instructionPath(client), file = basename(path);
|
|
97
|
+
try {
|
|
98
|
+
const text = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
99
|
+
const current = managed(text);
|
|
100
|
+
if (current && text.slice(current.start, current.end) !== block(context.pkg.version, context.guidance, current.created)) findings.push(finding("ALT-SETUP-001", "deterministic", "fail", `${file} points to different guidance`, "Setup matches installed version and location", `altitude init --client ${client} --apply`, "altitude doctor --json"));
|
|
101
|
+
else findings.push(finding("ALT-SETUP-001", "deterministic", current ? "pass" : "not-configured", `${client}: ${current ? "managed pointer matches" : "no managed pointer"}`, "Explicit setup when agent integration is desired", `altitude init --client ${client}`, "Restart client and inspect loaded instructions."));
|
|
102
|
+
} catch (e) {
|
|
103
|
+
findings.push(finding("ALT-SETUP-001", "deterministic", "fail", `${file}: ${e.message}`, "One intact managed block", "Reconcile edited/duplicate markers manually.", "altitude doctor --json"));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const rules = JSON.parse(readFileSync(resolve(context.guidance, "rules.json"), "utf8")).rules;
|
|
107
|
+
for (const r of rules.filter((r2) => r2.diagnosticClass !== "deterministic")) findings.push(finding(r.id, r.diagnosticClass, "unverified", "CLI has not exercised application behavior or conducted human review.", r.title, r.repair, r.verification));
|
|
108
|
+
const ok = !findings.some((f) => f.kind === "deterministic" && f.status === "fail");
|
|
109
|
+
emit({ command: "doctor", packageVersion: context.pkg.version, guidanceVersion: context.index.version, ok, scope: "Installation and managed pointers only; not accessibility or usability certification.", findings });
|
|
110
|
+
if (!ok) process.exitCode = 1;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
if (command === "help" || command === "--help") console.log("altitude init --client codex|claude|all [--apply] [--remove]\naltitude patterns [intent] [--json]\naltitude explain RULE-ID [--json]\naltitude doctor [--json]\nAll commands resolve the installed package from --cwd PATH (default current directory).");
|
|
114
|
+
else {
|
|
115
|
+
const context = installed();
|
|
116
|
+
if (command === "init") init(context);
|
|
117
|
+
else if (command === "doctor") doctor(context);
|
|
118
|
+
else if (command === "patterns") {
|
|
119
|
+
const words = args.filter((v, i) => !v.startsWith("--") && args[i - 1] !== "--cwd").join(" ").toLowerCase().split(/\W+/).filter(Boolean);
|
|
120
|
+
const patterns = context.index.patterns.map((p) => ({ ...p, score: words.reduce((n, w) => n + (p.intents.some((i) => i === w || i.startsWith(w)) ? 1 : 0), 0) })).filter((p) => !words.length || p.score).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));
|
|
121
|
+
if (json) emit({ version: context.pkg.version, patterns });
|
|
122
|
+
else console.log(patterns.length ? patterns.map((p) => `${p.id}: ${p.purpose}
|
|
123
|
+
${resolve(context.guidance, p.document)}`).join("\n") : "No pattern matched. Run altitude patterns to browse the catalog.");
|
|
124
|
+
} else if (command === "explain") {
|
|
125
|
+
const id = args[0];
|
|
126
|
+
const rule = JSON.parse(readFileSync(resolve(context.guidance, "rules.json"), "utf8")).rules.find((r) => r.id === id);
|
|
127
|
+
if (!rule) throw new Error(`Unknown rule: ${id}`);
|
|
128
|
+
emit({ version: context.pkg.version, ...rule });
|
|
129
|
+
} else throw new Error(`Unknown command: ${command}`);
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
emit({ ok: false, findings: [finding("ALT-SETUP-001", "deterministic", "fail", error.message, "Installed altitude-design with coherent guidance and valid command arguments", "Install altitude-design locally; check arguments and managed instruction blocks.", "altitude doctor --json")] });
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Altitude framework
|
|
2
|
+
|
|
3
|
+
Start from the person's task. Read only the relevant pattern below, its linked rules, and the public declarations. The installed copy matches the package version; `altitude doctor --json` checks that connection. Guidance supports judgment; it does not certify an application.
|
|
4
|
+
|
|
5
|
+
Composing a new screen? Choose its frame from the task with [screen layout](patterns/screen-layout.md) first: name the task, the one thing that leads and the one primary action. The [app skeleton](app-skeleton.md) is one of its frames, for working through many similar records: shell, page header, a filtered and paged table, a record in a sheet, and settings, composed correctly.
|
|
6
|
+
|
|
7
|
+
| Intent | Focused contract |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Edit a record | [Edit record](patterns/edit-record.md) |
|
|
10
|
+
| Search, filter or browse records | [Async collection](patterns/async-collection.md) |
|
|
11
|
+
| Delete, revoke, publish or recover | [Consequential action](patterns/consequential-action.md) |
|
|
12
|
+
| Review answers and finish a process | [Review and submit](patterns/review-submit.md) |
|
|
13
|
+
| A settings page: apply now, save together, danger zone | [Settings](patterns/settings.md) |
|
|
14
|
+
| Invite people, change roles, remove access | [Members](patterns/members.md) |
|
|
15
|
+
| Usage, plan changes, invoices | [Billing](patterns/billing.md) |
|
|
16
|
+
| Sign in, sign up, two-factor, reset | [Auth](patterns/auth.md) |
|
|
17
|
+
| An audit log or a record's activity | [Audit log](patterns/audit-log.md) |
|
|
18
|
+
| Import records from a CSV file | [Import](patterns/import.md) |
|
|
19
|
+
| Autosave, offline, conflicts, session expiry | [Sync](patterns/sync.md) |
|
|
20
|
+
| API keys, webhooks, integrations | [Developer settings](patterns/developer-settings.md) |
|
|
21
|
+
| An agent that proposes and acts | [Agent action](patterns/agent-action.md) |
|
|
22
|
+
| A conversation with an assistant (send, stream, stop, retry, limits) | [Assistant conversation](patterns/assistant-conversation.md) |
|
|
23
|
+
| Setup checklist, empty states, tours, what's new | [Onboarding](patterns/onboarding.md) |
|
|
24
|
+
| A new screen: choose its frame (editor, decision, report, triage, flow, records) from the task | [Screen layout](patterns/screen-layout.md) |
|
|
25
|
+
|
|
26
|
+
Before implementation, capture a short design record in the application's normal documentation: user goal, audience, primary action, consequence, data shape, selected patterns, applicable states, and unresolved product decisions. Infer routine details from the existing product. Do not invent permissions, persistence, cancellation, rollback or undo. Ask only when an unknown changes consequences or the task itself.
|
|
27
|
+
|
|
28
|
+
Use `altitude patterns "edit settings" --json` to discover contracts and `altitude explain ALT-EDIT-001` for a rule's scope and evidence. Read [principles](principles.md) for ownership and [evidence.json](evidence.json) for source authority. The generated `index.json` and `llms.txt` route to these same sources; they are not separately authored manuals.
|
|
29
|
+
|
|
30
|
+
Compose existing primitives and small workflow hooks from the main `altitude-design` export inside one `AltitudeProvider`. Import a package stylesheet. The application supplies routes, business validation and services. Verify delayed operations, rejection, retry, cancellation and stale responses where applicable; include keyboard and manual assistive-technology review. Automated checks cannot establish complete accessibility or task suitability.
|
|
31
|
+
|
|
32
|
+
For explicit agent setup, preview `npm exec -- altitude init --client codex` (or `claude`), then use `--apply`. Full setup and removal instructions are shipped as `agent-setup.md`, generated from the repository’s `docs/framework/AGENT-SETUP.md`. No installation hook writes project instructions.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Connect installed guidance to an agent
|
|
2
|
+
|
|
3
|
+
Install `altitude-design`, then run the installed binary from the consumer project root. The Node CLI has no runtime React dependency and no install hook. It never writes to a project merely because the package is installed.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm exec -- altitude init --client codex
|
|
7
|
+
npm exec -- altitude init --client codex --apply
|
|
8
|
+
npm exec -- altitude init --client claude --apply
|
|
9
|
+
npm exec -- altitude patterns "edit settings" --json
|
|
10
|
+
npm exec -- altitude explain ALT-EDIT-001
|
|
11
|
+
npm exec -- altitude doctor --json
|
|
12
|
+
npm exec -- altitude init --client codex --remove
|
|
13
|
+
npm exec -- altitude init --client codex --remove --apply
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`init` defaults to a preview, including the exact before/after text. `--apply` applies that preview. `--client all` targets both clients. Repeating setup makes no change. Removal removes only the managed block, restoring surrounding bytes; a file created by setup is removed only if nothing else remains. User-edited managed blocks, malformed markers and symlinks are rejected for manual reconciliation. Existing instructions outside the block are preserved. Run setup again after upgrading the installed package. Use `--cwd PATH` to target an explicit project directory. Resolution uses that directory's installed `altitude-design/package.json`, never the version fetched by a different CLI invocation.
|
|
17
|
+
|
|
18
|
+
The Codex adapter writes a compact routing block to project `AGENTS.md` (or an existing nonempty `AGENTS.override.md`, which Codex gives precedence); the Claude Code adapter writes it to project `CLAUDE.md`. Neither assumes instruction files under `node_modules` are automatically discovered. The routing block points at version-matched local focused documents rather than importing the complete manual. Restart the agent session after setup. Confirm Codex reports the project instruction file and Claude Code's `/context` lists it under Memory files; then ask an ordinary product question and check that the relevant pattern is read. Instructions are context, not enforcement, and broader or more specific instructions may affect discovery.
|
|
19
|
+
|
|
20
|
+
Mechanisms verified against official documentation on 2026-10-23: [Codex AGENTS.md](https://learn.chatgpt.com/docs/agent-configuration/agents-md) describes root-to-working-directory instruction discovery, override precedence and size limits; [Claude Code memory](https://code.claude.com/docs/en/memory) documents project `CLAUDE.md` loading and `/context` inspection. The adapter tests verify files and round trips, not successful behavior of every client release. Claude Code also documents AGENTS.md support; CLAUDE.md remains the explicit adapter target.
|
|
21
|
+
|
|
22
|
+
`doctor` reports stable rule IDs, observed evidence, expected behavior, repairs and verification. It returns a failing exit code only for deterministic installation/setup defects; service integration and contextual obligations remain visibly unverified. It does not inspect an application's service behavior or certify accessibility. Guidance remains usable offline through `altitude-design/guidance`, `altitude-design/guidance/*`, and physical `node_modules/altitude-design/dist/guidance` files. Tooling stays outside browser imports.
|