@botiverse/raft-ui 0.72.0 → 0.74.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 +39 -0
- package/dist/components/activity-inbox/activity-inbox-shell.d.mts +6 -3
- package/dist/components/activity-inbox/activity-inbox-shell.mjs +33 -14
- package/dist/components/activity-inbox/activity-inbox-shell.recipe.mjs +6 -1
- package/dist/components/announcement-dialog/announcement-dialog.d.mts +2 -1
- package/dist/components/announcement-dialog/announcement-dialog.mjs +5 -4
- package/dist/components/choice-list/choice-list.mjs +4 -1
- package/dist/components/choice-list/choice-list.recipe.mjs +2 -2
- package/dist/components/combobox-select/combobox-select.css +2 -0
- package/dist/components/composer/composer-suggestion-list.d.mts +5 -2
- package/dist/components/composer/composer-suggestion-list.mjs +10 -8
- package/dist/components/composer/composer.recipe.mjs +1 -1
- package/dist/components/dialog/dialog.d.mts +5 -3
- package/dist/components/dialog/dialog.mjs +16 -10
- package/dist/components/files/files.d.mts +5 -2
- package/dist/components/files/files.mjs +11 -2
- package/dist/components/files/files.recipe.mjs +1 -1
- package/dist/components/filter-chip/filter-chip.mjs +2 -1
- package/dist/components/markdown/markdown-parts.d.mts +1 -1
- package/dist/components/markdown/markdown-parts.mjs +1 -1
- package/dist/components/message-action-card/message-action-card-content.recipe.mjs +2 -1
- package/dist/components/message-action-card/message-action-card.d.mts +6 -4
- package/dist/components/message-action-card/message-action-card.mjs +14 -27
- package/dist/components/message-list/message-list.mjs +3 -3
- package/dist/components/mobile-nav/mobile-nav-server.d.mts +4 -2
- package/dist/components/mobile-nav/mobile-nav-server.mjs +9 -5
- package/dist/components/notification-center/notification-center.d.mts +5 -2
- package/dist/components/notification-center/notification-center.mjs +10 -8
- package/dist/components/panel/panel-action.mjs +1 -1
- package/dist/components/panel/panel.d.mts +10 -2
- package/dist/components/panel/panel.mjs +26 -3
- package/dist/components/panel/panel.recipe.mjs +2 -1
- package/dist/components/scroll-area/scroll-area.css +27 -10
- package/dist/components/scroll-area/types.d.mts +3 -1
- package/dist/components/scroll-area/use-scroll-area-container.d.mts +2 -1
- package/dist/components/search/search.d.mts +5 -3
- package/dist/components/search/search.mjs +9 -10
- package/dist/components/search/search.recipe.mjs +1 -1
- package/dist/components/segmented-control/segmented-control.mjs +1 -1
- package/dist/components/sidebar/sidebar.mjs +1 -1
- package/dist/components/tabs/tabs.mjs +1 -1
- package/dist/components/tasks/tasks-panel.d.mts +6 -2
- package/dist/components/tasks/tasks-panel.mjs +10 -7
- package/dist/components/tasks/tasks-panel.recipe.mjs +1 -1
- package/dist/components/toggle-group/toggle-group.mjs +1 -1
- package/dist/components/virtual-list/styles/virtual-list.css +3 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/lib/use-scrollbar-size.d.mts +3 -0
- package/dist/lib/use-scrollbar-size.mjs +3 -0
- package/dist/lint/prefer-scroll-area.d.mts +75 -0
- package/dist/lint/prefer-scroll-area.mjs +157 -0
- package/dist/lint/recommended.json +6 -0
- package/dist/lint.d.mts +22 -0
- package/dist/lint.mjs +29 -0
- package/dist/styles.css +3 -2
- package/package.json +6 -1
- package/skills/raft-ui-guide/SKILL.md +1 -0
- package/skills/raft-ui-guide/rules/technical-overview.md +1 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//#region src/lint/prefer-scroll-area.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* raft-ui/prefer-scroll-area: every region that scrolls is a ScrollArea
|
|
4
|
+
* (scroll-area.md#native-scrolling), so a native overflow that makes an
|
|
5
|
+
* element scroll is reported where an app writes it.
|
|
6
|
+
*
|
|
7
|
+
* Reported:
|
|
8
|
+
* - a native-scrolling Tailwind class (`overflow`, `overflow-x` or `overflow-y`
|
|
9
|
+
* set to auto or scroll, with any variant prefix, `!`, or as an arbitrary
|
|
10
|
+
* property) in a string or template literal that is a class: the value of a
|
|
11
|
+
* `className`, `class` or `*ClassName` JSX attribute, or an argument of
|
|
12
|
+
* `cn`, `clsx`, `cx`, `tv`, `cva`, `twMerge`, `twJoin` or `classNames`,
|
|
13
|
+
* through conditionals, `&&`, arrays, objects (keys and values) and `+`;
|
|
14
|
+
* - an inline `style={{ overflow | overflowX | overflowY: "auto" | "scroll" }}`.
|
|
15
|
+
*
|
|
16
|
+
* Allowed with a `raft-ui: native-scroll <reason>` comment, line or block, on
|
|
17
|
+
* the line above the reported string (or at the end of its line): it covers
|
|
18
|
+
* the string that starts on that line only, not the rest of the call or the
|
|
19
|
+
* attribute it is in, so a class added to a multi-line `cn(...)` later is
|
|
20
|
+
* still reported. For an inline style, the line of its property. A comment
|
|
21
|
+
* without a reason doesn't count.
|
|
22
|
+
*
|
|
23
|
+
* It looks only at literals, with no scope or type information: a class built
|
|
24
|
+
* in a variable outside these calls isn't seen.
|
|
25
|
+
*/
|
|
26
|
+
export interface Position {
|
|
27
|
+
line: number;
|
|
28
|
+
column: number;
|
|
29
|
+
}
|
|
30
|
+
export interface Node {
|
|
31
|
+
type: string;
|
|
32
|
+
parent?: Node | null;
|
|
33
|
+
loc?: {
|
|
34
|
+
start: Position;
|
|
35
|
+
end: Position;
|
|
36
|
+
};
|
|
37
|
+
range?: [number, number];
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
}
|
|
40
|
+
export interface Comment {
|
|
41
|
+
type: string;
|
|
42
|
+
value: string;
|
|
43
|
+
loc?: {
|
|
44
|
+
start: Position;
|
|
45
|
+
end: Position;
|
|
46
|
+
};
|
|
47
|
+
range?: [number, number];
|
|
48
|
+
}
|
|
49
|
+
export interface SourceCode {
|
|
50
|
+
getAllComments(): Comment[];
|
|
51
|
+
getLocFromIndex(index: number): Position;
|
|
52
|
+
}
|
|
53
|
+
export interface RuleContext {
|
|
54
|
+
sourceCode?: SourceCode;
|
|
55
|
+
getSourceCode?: () => SourceCode;
|
|
56
|
+
report(descriptor: {
|
|
57
|
+
node: Node;
|
|
58
|
+
messageId: string;
|
|
59
|
+
}): void;
|
|
60
|
+
}
|
|
61
|
+
export type RuleVisitor = Record<string, (node: Node) => void>;
|
|
62
|
+
/** An ESLint rule, the format Oxlint's JS plugins take. */
|
|
63
|
+
export interface RuleModule {
|
|
64
|
+
meta: {
|
|
65
|
+
type: "problem" | "suggestion" | "layout";
|
|
66
|
+
docs: {
|
|
67
|
+
description: string;
|
|
68
|
+
url: string;
|
|
69
|
+
};
|
|
70
|
+
messages: Record<string, string>;
|
|
71
|
+
schema: readonly unknown[];
|
|
72
|
+
};
|
|
73
|
+
create(context: RuleContext): RuleVisitor;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region src/lint/prefer-scroll-area.ts
|
|
2
|
+
const NATIVE_SCROLL_CLASS = /(?<![\w-])overflow(?:-[xy])?-(?:auto|scroll)(?![\w-])/;
|
|
3
|
+
const NATIVE_SCROLL_ARBITRARY = /\[overflow(?:-[xy])?:[^\]]*\b(?:auto|scroll)\b[^\]]*\]/;
|
|
4
|
+
const NATIVE_SCROLL_STYLE_KEYS = /* @__PURE__ */ new Set([
|
|
5
|
+
"overflow",
|
|
6
|
+
"overflowX",
|
|
7
|
+
"overflowY"
|
|
8
|
+
]);
|
|
9
|
+
const NATIVE_SCROLL_STYLE_VALUES = /* @__PURE__ */ new Set(["auto", "scroll"]);
|
|
10
|
+
const CLASS_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
11
|
+
"cn",
|
|
12
|
+
"clsx",
|
|
13
|
+
"cx",
|
|
14
|
+
"tv",
|
|
15
|
+
"cva",
|
|
16
|
+
"twMerge",
|
|
17
|
+
"twJoin",
|
|
18
|
+
"classNames",
|
|
19
|
+
"classnames"
|
|
20
|
+
]);
|
|
21
|
+
const CLASS_ATTRIBUTE = /^(?:class|className|\w+ClassName)$/;
|
|
22
|
+
const PASS_THROUGH = /* @__PURE__ */ new Set([
|
|
23
|
+
"ArrayExpression",
|
|
24
|
+
"BinaryExpression",
|
|
25
|
+
"ConditionalExpression",
|
|
26
|
+
"JSXExpressionContainer",
|
|
27
|
+
"LogicalExpression",
|
|
28
|
+
"ObjectExpression",
|
|
29
|
+
"ParenthesizedExpression",
|
|
30
|
+
"Property",
|
|
31
|
+
"SpreadElement",
|
|
32
|
+
"TemplateLiteral",
|
|
33
|
+
"TSAsExpression",
|
|
34
|
+
"TSNonNullExpression",
|
|
35
|
+
"TSSatisfiesExpression"
|
|
36
|
+
]);
|
|
37
|
+
const ESCAPE = /\braft-ui:\s*native-scroll\s+\S/;
|
|
38
|
+
/** Whether a class string has a native-scrolling class in it. */
|
|
39
|
+
function hasNativeScrollClass(value) {
|
|
40
|
+
if (!value.includes("overflow")) return false;
|
|
41
|
+
return NATIVE_SCROLL_CLASS.test(value) || NATIVE_SCROLL_ARBITRARY.test(value);
|
|
42
|
+
}
|
|
43
|
+
function attributeName(node) {
|
|
44
|
+
const name = node.name;
|
|
45
|
+
return name?.type === "JSXIdentifier" ? name.name : void 0;
|
|
46
|
+
}
|
|
47
|
+
/** The attribute or call that makes a string a class, or undefined when it isn't one. */
|
|
48
|
+
function classContext(node) {
|
|
49
|
+
let child = node;
|
|
50
|
+
let parent = node.parent;
|
|
51
|
+
while (parent) {
|
|
52
|
+
if (parent.type === "JSXAttribute") {
|
|
53
|
+
const name = attributeName(parent);
|
|
54
|
+
return name !== void 0 && CLASS_ATTRIBUTE.test(name) ? parent : void 0;
|
|
55
|
+
}
|
|
56
|
+
if (parent.type === "CallExpression") {
|
|
57
|
+
const callee = parent.callee;
|
|
58
|
+
return callee.type === "Identifier" && CLASS_FUNCTIONS.has(callee.name) && parent.arguments.includes(child) ? parent : void 0;
|
|
59
|
+
}
|
|
60
|
+
if (!PASS_THROUGH.has(parent.type)) return void 0;
|
|
61
|
+
child = parent;
|
|
62
|
+
parent = parent.parent;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function stringValue(node) {
|
|
66
|
+
if (node.type === "Literal" && typeof node.value === "string") return node.value;
|
|
67
|
+
if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
|
|
68
|
+
const [quasi] = node.quasis;
|
|
69
|
+
const value = quasi?.value;
|
|
70
|
+
return value?.cooked ?? value?.raw;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** The string literals an inline style value can be: `"auto"`, `a ? "auto" : "hidden"`, `a && "auto"`. */
|
|
74
|
+
function styleValueStrings(node, out) {
|
|
75
|
+
if (node.type === "ConditionalExpression") {
|
|
76
|
+
styleValueStrings(node.consequent, out);
|
|
77
|
+
styleValueStrings(node.alternate, out);
|
|
78
|
+
} else if (node.type === "LogicalExpression") {
|
|
79
|
+
styleValueStrings(node.left, out);
|
|
80
|
+
styleValueStrings(node.right, out);
|
|
81
|
+
} else if (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") styleValueStrings(node.expression, out);
|
|
82
|
+
else if (stringValue(node) !== void 0) out.push(node);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
function propertyKey(property) {
|
|
86
|
+
const key = property.key;
|
|
87
|
+
if (property.computed) return stringValue(key);
|
|
88
|
+
return key.type === "Identifier" ? key.name : stringValue(key);
|
|
89
|
+
}
|
|
90
|
+
const preferScrollArea = {
|
|
91
|
+
meta: {
|
|
92
|
+
type: "suggestion",
|
|
93
|
+
docs: {
|
|
94
|
+
description: "Scrolling regions use ScrollArea from @botiverse/raft-ui, not a native overflow.",
|
|
95
|
+
url: "https://raft-design.botiverse.build/about/use-raft-ui/#lint-rules"
|
|
96
|
+
},
|
|
97
|
+
messages: { preferScrollArea: "Scrolling regions use ScrollArea from @botiverse/raft-ui (or PanelScrollViewport inside a Panel). If this one must scroll natively, say why in an `// raft-ui: native-scroll <reason>` comment on the line above. https://raft-design.botiverse.build/components/scroll-area/" },
|
|
98
|
+
schema: []
|
|
99
|
+
},
|
|
100
|
+
create(context) {
|
|
101
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode?.();
|
|
102
|
+
let escapeLines;
|
|
103
|
+
function line(index) {
|
|
104
|
+
return sourceCode.getLocFromIndex(index).line;
|
|
105
|
+
}
|
|
106
|
+
/** The lines an escape comment covers: the one it ends on and the next. */
|
|
107
|
+
function escaped() {
|
|
108
|
+
if (escapeLines) return escapeLines;
|
|
109
|
+
escapeLines = /* @__PURE__ */ new Set();
|
|
110
|
+
for (const comment of sourceCode?.getAllComments() ?? []) {
|
|
111
|
+
if (!ESCAPE.test(comment.value)) continue;
|
|
112
|
+
const end = comment.loc?.end.line ?? line(comment.range[1]);
|
|
113
|
+
escapeLines.add(end);
|
|
114
|
+
escapeLines.add(end + 1);
|
|
115
|
+
}
|
|
116
|
+
return escapeLines;
|
|
117
|
+
}
|
|
118
|
+
function startLine(node) {
|
|
119
|
+
return node.loc?.start.line ?? line(node.range[0]);
|
|
120
|
+
}
|
|
121
|
+
/** Reports `node` unless an escape comment covers the line `anchor` starts on. */
|
|
122
|
+
function report(node, anchor) {
|
|
123
|
+
const lines = escaped();
|
|
124
|
+
if (lines.size > 0 && lines.has(startLine(anchor))) return;
|
|
125
|
+
context.report({
|
|
126
|
+
node,
|
|
127
|
+
messageId: "preferScrollArea"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function checkClassString(node, value) {
|
|
131
|
+
if (!hasNativeScrollClass(value)) return;
|
|
132
|
+
if (classContext(node)) report(node, node);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
Literal(node) {
|
|
136
|
+
if (typeof node.value === "string") checkClassString(node, node.value);
|
|
137
|
+
},
|
|
138
|
+
TemplateLiteral(node) {
|
|
139
|
+
checkClassString(node, node.quasis.map((quasi) => quasi.value.raw).join(" "));
|
|
140
|
+
},
|
|
141
|
+
JSXAttribute(node) {
|
|
142
|
+
if (attributeName(node) !== "style") return;
|
|
143
|
+
const value = node.value;
|
|
144
|
+
const expression = value?.type === "JSXExpressionContainer" ? value.expression : void 0;
|
|
145
|
+
if (expression?.type !== "ObjectExpression") return;
|
|
146
|
+
for (const property of expression.properties) {
|
|
147
|
+
if (property.type !== "Property") continue;
|
|
148
|
+
const key = propertyKey(property);
|
|
149
|
+
if (key === void 0 || !NATIVE_SCROLL_STYLE_KEYS.has(key)) continue;
|
|
150
|
+
for (const literal of styleValueStrings(property.value, [])) if (NATIVE_SCROLL_STYLE_VALUES.has(stringValue(literal).trim())) report(literal, property);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
export { hasNativeScrollClass, preferScrollArea };
|
package/dist/lint.d.mts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RuleContext, RuleModule, RuleVisitor } from "./lint/prefer-scroll-area.mjs";
|
|
2
|
+
//#region src/lint/index.d.ts
|
|
3
|
+
export interface RaftUiLintConfig {
|
|
4
|
+
name: string;
|
|
5
|
+
plugins: Record<string, RaftUiLintPlugin>;
|
|
6
|
+
rules: Record<string, "error" | "warn" | "off">;
|
|
7
|
+
}
|
|
8
|
+
export interface RaftUiLintPlugin {
|
|
9
|
+
meta: {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
rules: Record<string, RuleModule>;
|
|
13
|
+
configs: Record<string, RaftUiLintConfig>;
|
|
14
|
+
}
|
|
15
|
+
export declare const rules: Record<string, RuleModule>;
|
|
16
|
+
/** Every rule of the plugin with its severity, as `recommended.json` lists them. */
|
|
17
|
+
export declare const recommendedRules: Record<string, "error">;
|
|
18
|
+
declare const plugin: RaftUiLintPlugin;
|
|
19
|
+
/** ESLint flat config: `export default [raftUi.configs.recommended]`. */
|
|
20
|
+
export declare const recommended: RaftUiLintConfig;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { type RuleContext, type RuleModule, type RuleVisitor, plugin as default };
|
package/dist/lint.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { preferScrollArea } from "./lint/prefer-scroll-area.mjs";
|
|
2
|
+
//#region src/lint/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* raft-ui's lint plugin: the Raft Design System's rules for the code of an app
|
|
5
|
+
* built on raft-ui, in the ESLint plugin format, which Oxlint loads as a JS
|
|
6
|
+
* plugin (`jsPlugins`). Published as `@botiverse/raft-ui/lint`.
|
|
7
|
+
*
|
|
8
|
+
* Enable every rule at once by extending `recommended.json` from the same
|
|
9
|
+
* package (Oxlint) or adding `configs.recommended` (ESLint flat config), so a
|
|
10
|
+
* rule added in a later release reaches the app with the upgrade. See
|
|
11
|
+
* design/about/use-raft-ui.md#lint-rules.
|
|
12
|
+
*/
|
|
13
|
+
const rules = { "prefer-scroll-area": preferScrollArea };
|
|
14
|
+
/** Every rule of the plugin with its severity, as `recommended.json` lists them. */
|
|
15
|
+
const recommendedRules = { "raft-ui/prefer-scroll-area": "error" };
|
|
16
|
+
const plugin = {
|
|
17
|
+
meta: { name: "raft-ui" },
|
|
18
|
+
rules,
|
|
19
|
+
configs: {}
|
|
20
|
+
};
|
|
21
|
+
/** ESLint flat config: `export default [raftUi.configs.recommended]`. */
|
|
22
|
+
const recommended = {
|
|
23
|
+
name: "raft-ui/recommended",
|
|
24
|
+
plugins: { "raft-ui": plugin },
|
|
25
|
+
rules: recommendedRules
|
|
26
|
+
};
|
|
27
|
+
plugin.configs.recommended = recommended;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { plugin as default, recommended, recommendedRules, rules };
|
package/dist/styles.css
CHANGED
|
@@ -893,8 +893,9 @@ textarea:-webkit-autofill:disabled {
|
|
|
893
893
|
--list-cell: 1;
|
|
894
894
|
}
|
|
895
895
|
|
|
896
|
-
/*
|
|
897
|
-
lists.md
|
|
896
|
+
/* For a native scroller of list cells that can't be a ScrollArea
|
|
897
|
+
(design/patterns/lists.md; raft-ui's own list scrollers are ScrollAreas,
|
|
898
|
+
whose overlay scrollbar takes no room): an 8px classic scrollbar with a 4px thumb, so a cell's
|
|
898
899
|
end inset can come out of the scrollbar's own width and its fill sits 8px
|
|
899
900
|
from both edges of the list. Styling ::-webkit-scrollbar makes Chromium
|
|
900
901
|
draw this classic, always-visible 8px bar even where the platform's own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botiverse/raft-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.74.0",
|
|
4
4
|
"description": "React components and CSS foundations for the Raft Design System.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -46,6 +46,11 @@
|
|
|
46
46
|
"types": "./dist/wip.d.mts",
|
|
47
47
|
"default": "./dist/wip.mjs"
|
|
48
48
|
},
|
|
49
|
+
"./lint": {
|
|
50
|
+
"types": "./dist/lint.d.mts",
|
|
51
|
+
"default": "./dist/lint.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./lint/recommended.json": "./dist/lint/recommended.json",
|
|
49
54
|
"./fonts.css": "./dist/fonts.css",
|
|
50
55
|
"./styles.css": "./dist/styles.css",
|
|
51
56
|
"./package.json": "./package.json",
|
|
@@ -90,6 +90,7 @@ When reviewing or editing code that uses raft-ui, check:
|
|
|
90
90
|
- [ ] Menu rows are `…Item` parts, not raw `<button>`s; raw buttons drop out of keyboard navigation
|
|
91
91
|
- [ ] Product state (upload, permissions, read/unread) lives in the app; the component renders parts, not a `state` prop
|
|
92
92
|
- [ ] No shadow written as `shadow-[var(--…)]`: named utility or fully literal
|
|
93
|
+
- [ ] Every region that scrolls is a `ScrollArea` (or `PanelScrollViewport` in a Panel), not `overflow-auto` / `overflow-scroll`; a native scroller kept on purpose has a `// raft-ui: native-scroll <reason>` comment. The `raft-ui/prefer-scroll-area` lint rule checks it: https://raft-design.botiverse.build/about/use-raft-ui.md#lint-rules
|
|
93
94
|
|
|
94
95
|
## Stability
|
|
95
96
|
|
|
@@ -19,6 +19,7 @@ description: "raft-ui's technical foundations, package contents, and integration
|
|
|
19
19
|
| `@botiverse/raft-ui/foundation.css` | Native CSS theme variables |
|
|
20
20
|
| `@botiverse/raft-ui/styles.css` | Tailwind integration |
|
|
21
21
|
| `@botiverse/raft-ui/fonts.css` | Optional web fonts |
|
|
22
|
+
| `@botiverse/raft-ui/lint` | Lint plugin with the DS rules for apps |
|
|
22
23
|
|
|
23
24
|
Component declarations live in `dist/index.d.mts` (see [API lookup](./lookup.md)). Version-matched Markdown guides and optional `raft-ui-guide` / `raft-ui-critique` skills ship in `skills/`.
|
|
24
25
|
|