@kerfjs/ui 5.0.0-beta.69 → 5.0.0-beta.70
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/ai/component-catalog.json +11 -1
- package/ai/component-catalog.schema.json +1 -1
- package/ai/component-composition.json +1 -0
- package/ai/component-composition.schema.json +1 -1
- package/ai/components/lucide-icon.md +12 -0
- package/ai/public-api-signatures-v1.md +7 -3
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/component-ownership.d.mts +16 -0
- package/analyzer/component-ownership.mjs +87 -4
- package/analyzer/index.d.mts +2 -0
- package/analyzer/index.mjs +490 -9
- package/dist/catalog.js +3 -3
- package/dist/{chunk-2ZOLX3IE.js → chunk-DB5ADJKF.js} +2 -2
- package/dist/{chunk-2ZOLX3IE.js.map → chunk-DB5ADJKF.js.map} +1 -1
- package/dist/{chunk-X3X4KRDK.js → chunk-DC6CN2DS.js} +2 -2
- package/dist/{chunk-X3X4KRDK.js.map → chunk-DC6CN2DS.js.map} +1 -1
- package/dist/{chunk-AUVG54KC.js → chunk-G4S2QU6V.js} +2 -2
- package/dist/{chunk-AUVG54KC.js.map → chunk-G4S2QU6V.js.map} +1 -1
- package/dist/{chunk-CRVDF4A6.js → chunk-K67Y2JNF.js} +2 -2
- package/dist/{chunk-CRVDF4A6.js.map → chunk-K67Y2JNF.js.map} +1 -1
- package/dist/{chunk-H7IODXGY.js → chunk-KCCEH7RF.js} +3 -3
- package/dist/{chunk-H7IODXGY.js.map → chunk-KCCEH7RF.js.map} +1 -1
- package/dist/{chunk-3BCJGM36.js → chunk-M6DEEBEF.js} +2 -2
- package/dist/{chunk-3BCJGM36.js.map → chunk-M6DEEBEF.js.map} +1 -1
- package/dist/{chunk-X3TPECWG.js → chunk-OXO2QJWV.js} +3 -1
- package/dist/chunk-OXO2QJWV.js.map +1 -0
- package/dist/{chunk-B3XWUX3A.js → chunk-RNQNEENY.js} +2 -2
- package/dist/{chunk-B3XWUX3A.js.map → chunk-RNQNEENY.js.map} +1 -1
- package/dist/{chunk-PQZPVBP4.js → chunk-RVERAFFY.js} +2 -2
- package/dist/{chunk-PQZPVBP4.js.map → chunk-RVERAFFY.js.map} +1 -1
- package/dist/{chunk-UA6JW52D.js → chunk-T2E5WBCZ.js} +110 -5
- package/dist/chunk-T2E5WBCZ.js.map +1 -0
- package/dist/{chunk-MOSIE4Z2.js → chunk-WTSNV5RG.js} +3 -2
- package/dist/chunk-WTSNV5RG.js.map +1 -0
- package/dist/collapsible-panel.js +3 -3
- package/dist/disclosure-arrow.js +1 -1
- package/dist/index.js +8 -8
- package/dist/list-header.js +1 -1
- package/dist/lucide-icon.d.ts +3 -1
- package/dist/lucide-icon.js +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/select.js +1 -1
- package/dist/split-view.js +1 -1
- package/dist/styles/app-tab.css +4 -0
- package/dist/styles/tab-bar.css +8 -0
- package/dist/styles/toolbar-control-group.css +1 -1
- package/dist/tab-bar.d.ts +3 -1
- package/dist/tab-bar.js +1 -1
- package/dist/token-search-field.js +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.js +1 -1
- package/docs/component-contract.md +16 -3
- package/docs/component-selection.md +8 -1
- package/docs/ui-analyzer.md +30 -9
- package/docs/ui-doctor.md +15 -6
- package/doctor/config.schema.json +2 -0
- package/doctor/index.d.mts +2 -0
- package/doctor/index.mjs +21 -0
- package/package.json +1 -1
- package/dist/chunk-MOSIE4Z2.js.map +0 -1
- package/dist/chunk-UA6JW52D.js.map +0 -1
- package/dist/chunk-X3TPECWG.js.map +0 -1
|
@@ -159,7 +159,16 @@
|
|
|
159
159
|
],
|
|
160
160
|
"variants": [
|
|
161
161
|
"decorative",
|
|
162
|
-
"labeled"
|
|
162
|
+
"labeled",
|
|
163
|
+
"outline (default appearance)",
|
|
164
|
+
"solid (appearance=solid)"
|
|
165
|
+
],
|
|
166
|
+
"usageExamples": [
|
|
167
|
+
{
|
|
168
|
+
"title": "Solid selected glyph",
|
|
169
|
+
"description": "The solid appearance fills a compatible Lucide glyph with currentColor while retaining its stroke and accessible name policy.",
|
|
170
|
+
"code": "<LucideIcon icon={Star} name=\"star\" appearance=\"solid\" />"
|
|
171
|
+
}
|
|
163
172
|
],
|
|
164
173
|
"accessibility": [
|
|
165
174
|
"Decorative icons are aria-hidden; meaningful icons require a label."
|
|
@@ -4665,6 +4674,7 @@
|
|
|
4665
4674
|
{
|
|
4666
4675
|
"id": "loading-spinner",
|
|
4667
4676
|
"name": "LoadingSpinner",
|
|
4677
|
+
"rootElement": "svg",
|
|
4668
4678
|
"category": "Feedback",
|
|
4669
4679
|
"kind": "component",
|
|
4670
4680
|
"source": "kerf",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"accessibility": { "type": "array", "items": { "type": "string" } },
|
|
61
61
|
"publicClasses": { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
|
|
62
62
|
"placeableClasses": { "description": "Public classes an application may place on its own elements (layout utilities, a document root, or item geometry on a non-div carrier). Every other public class is component anatomy: render the component instead.", "type": "array", "items": { "type": "string" }, "uniqueItems": true },
|
|
63
|
-
"rootElement": { "description": "The intrinsic element the component renders at its root. Required
|
|
63
|
+
"rootElement": { "description": "The intrinsic element the component renders at its root. Required when a component renders placeableClasses; also enables classless child-root ownership checks.", "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" },
|
|
64
64
|
"publicTokens": { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
|
|
65
65
|
"cssValueProps": { "type": "array", "items": { "$ref": "#/$defs/cssValueProp" }, "uniqueItems": true },
|
|
66
66
|
"geometry": { "$ref": "#/$defs/geometry" },
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
"rootElement": {
|
|
334
334
|
"type": "string",
|
|
335
335
|
"pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
|
|
336
|
-
"description": "The intrinsic element the component renders at its root.
|
|
336
|
+
"description": "The intrinsic element the component renders at its root. It identifies composed child roots for ownership checks; a placeableClasses class on a plain element of this tag recreates the component, while the class stays placeable on another carrier."
|
|
337
337
|
},
|
|
338
338
|
"publicTokens": { "$ref": "#/$defs/stringList" },
|
|
339
339
|
"publicParts": { "$ref": "#/$defs/stringList" }
|
|
@@ -32,6 +32,8 @@ Exact prop names and types: [`@kerfjs/ui/lucide-icon`](../public-api-signatures-
|
|
|
32
32
|
|
|
33
33
|
- decorative
|
|
34
34
|
- labeled
|
|
35
|
+
- outline (default appearance)
|
|
36
|
+
- solid (appearance=solid)
|
|
35
37
|
|
|
36
38
|
## Composition
|
|
37
39
|
|
|
@@ -53,6 +55,16 @@ Margin: none · border: none · padding: none (layout role: foundation). `self`
|
|
|
53
55
|
|
|
54
56
|
- Decorative icons are aria-hidden; meaningful icons require a label.
|
|
55
57
|
|
|
58
|
+
## Usage examples
|
|
59
|
+
|
|
60
|
+
### Solid selected glyph
|
|
61
|
+
|
|
62
|
+
The solid appearance fills a compatible Lucide glyph with currentColor while retaining its stroke and accessible name policy.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<LucideIcon icon={Star} name="star" appearance="solid" />
|
|
66
|
+
```
|
|
67
|
+
|
|
56
68
|
## Styling boundary
|
|
57
69
|
|
|
58
70
|
The component owns its own styles. Configure it through its props and variants; do not override its internals.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.70` and `kerfjs@5.0.0-beta.70`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/css-values`
|
|
6
6
|
|
|
@@ -1110,11 +1110,13 @@ interface TabBarProps {
|
|
|
1110
1110
|
iconOnlyAt?: TabBarIconOnlyAt;
|
|
1111
1111
|
/** Keep a trailing action beside the final tab or at the far edge of the bar. */
|
|
1112
1112
|
trailingPlacement?: TabBarTrailingPlacement;
|
|
1113
|
+
/** Settle scrolling peers at whole-tab starts; wireTabBars measures a pinned leading tab's inset. */
|
|
1114
|
+
snapTabs?: boolean;
|
|
1113
1115
|
/** Native named-slot assignment when composed inside a web component. */
|
|
1114
1116
|
slot?: string;
|
|
1115
1117
|
}
|
|
1116
1118
|
/** Render a controlled tab strip. The application owns selection, order, and persistence. */
|
|
1117
|
-
declare function TabBar({ id, label, children, leading, trailing, end, className, activation, allocation, presentation, iconOnlyAt, trailingPlacement, slot, }: TabBarProps): kerfjs.SafeHtml;
|
|
1119
|
+
declare function TabBar({ id, label, children, leading, trailing, end, className, activation, allocation, presentation, iconOnlyAt, trailingPlacement, snapTabs, slot, }: TabBarProps): kerfjs.SafeHtml;
|
|
1118
1120
|
|
|
1119
1121
|
export { type TabActivation, TabBar, type TabBarAllocation, type TabBarIconOnlyAt, type TabBarPresentation, type TabBarProps, type TabBarTrailingPlacement };
|
|
1120
1122
|
```
|
|
@@ -3258,6 +3260,8 @@ type LucideIconSize = 'xs' | 's' | 'm' | 'l' | 'xl' | number;
|
|
|
3258
3260
|
interface LucideIconProps {
|
|
3259
3261
|
icon: LucideNode;
|
|
3260
3262
|
name: string;
|
|
3263
|
+
/** Outline by default; solid fills compatible glyphs with the current text color. */
|
|
3264
|
+
appearance?: 'outline' | 'solid';
|
|
3261
3265
|
className?: string;
|
|
3262
3266
|
label?: string;
|
|
3263
3267
|
/** Named icon scale or positive pixel size, converted to rem. Omit for 1em. */
|
|
@@ -3266,7 +3270,7 @@ interface LucideIconProps {
|
|
|
3266
3270
|
slot?: string;
|
|
3267
3271
|
}
|
|
3268
3272
|
/** Render a Lucide-compatible icon node without copying icon SVG strings. */
|
|
3269
|
-
declare function LucideIcon({ icon, name, className, label, size, slot, }: LucideIconProps): kerfjs.SafeHtml;
|
|
3273
|
+
declare function LucideIcon({ icon, name, appearance, className, label, size, slot, }: LucideIconProps): kerfjs.SafeHtml;
|
|
3270
3274
|
|
|
3271
3275
|
export { LucideIcon, type LucideIconProps, type LucideIconSize, type LucideNode };
|
|
3272
3276
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.70` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
|
@@ -33,7 +33,23 @@ export function restyledComponents(
|
|
|
33
33
|
selectorList: string,
|
|
34
34
|
facts: ComponentOwnershipFacts,
|
|
35
35
|
isForeign: (entry: OwnershipCatalogEntry) => boolean,
|
|
36
|
+
options?: {
|
|
37
|
+
componentMode?: boolean;
|
|
38
|
+
ownPackage?: string;
|
|
39
|
+
hooks?: Map<string, OwnershipCatalogEntry>;
|
|
40
|
+
composedChildren?: Map<string, OwnershipCatalogEntry>;
|
|
41
|
+
},
|
|
36
42
|
): RestyledComponent[];
|
|
43
|
+
export function contextualComponents(
|
|
44
|
+
selectorList: string,
|
|
45
|
+
facts: ComponentOwnershipFacts,
|
|
46
|
+
isForeign: (entry: OwnershipCatalogEntry) => boolean,
|
|
47
|
+
ownPackage: string | undefined,
|
|
48
|
+
): Array<{
|
|
49
|
+
entry: OwnershipCatalogEntry;
|
|
50
|
+
name: string;
|
|
51
|
+
position: 'subject' | 'ancestor' | 'sibling' | 'has' | 'is' | 'where' | 'not';
|
|
52
|
+
}>;
|
|
37
53
|
export function privateVariableOwner(
|
|
38
54
|
property: string,
|
|
39
55
|
facts: ComponentOwnershipFacts,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Downstream component-ownership facts for `kerf-ui-analyze` (`KUI-L019` –
|
|
3
|
-
* `KUI-
|
|
3
|
+
* `KUI-L023`): the consumer-side form of the package's own
|
|
4
4
|
* `check:css-ownership` rules.
|
|
5
5
|
*
|
|
6
6
|
* Components own their styles and are configured, never overridden. An
|
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
* application's stylesheet), but it never makes another package's component
|
|
10
10
|
* the subject of a rule, writes that component's private variables, overrides
|
|
11
11
|
* a token its typed prop configures, or restyles it through a hook class on
|
|
12
|
-
* its root.
|
|
13
|
-
* third-party
|
|
12
|
+
* its root. Facts come from composition and selection catalogs, plus optional
|
|
13
|
+
* source inference, so third-party packages get the same protection as
|
|
14
|
+
* `@kerfjs/ui`.
|
|
14
15
|
*/
|
|
15
16
|
import {
|
|
16
17
|
classNames,
|
|
17
18
|
complexSelectorParts,
|
|
18
19
|
dataComponents,
|
|
20
|
+
pseudoArguments,
|
|
19
21
|
subjectTypes,
|
|
20
22
|
withoutRelationalArguments,
|
|
21
23
|
} from './selectors.mjs';
|
|
@@ -95,7 +97,17 @@ export function componentOwnershipFacts(entries) {
|
|
|
95
97
|
* Returns `{ entry, via, name }` records; `isForeign(entry)` decides which
|
|
96
98
|
* entries the stylesheet does not own.
|
|
97
99
|
*/
|
|
98
|
-
export function restyledComponents(
|
|
100
|
+
export function restyledComponents(
|
|
101
|
+
selectorList,
|
|
102
|
+
facts,
|
|
103
|
+
isForeign,
|
|
104
|
+
{
|
|
105
|
+
componentMode = false,
|
|
106
|
+
ownPackage,
|
|
107
|
+
hooks = new Map(),
|
|
108
|
+
composedChildren = new Map(),
|
|
109
|
+
} = {},
|
|
110
|
+
) {
|
|
99
111
|
const found = [];
|
|
100
112
|
const seen = new Set();
|
|
101
113
|
const add = (entry, via, name) => {
|
|
@@ -127,10 +139,29 @@ export function restyledComponents(selectorList, facts, isForeign) {
|
|
|
127
139
|
// that component. Do not infer ownership through its root, where an app
|
|
128
140
|
// may place its own children, or through an app-named intermediate node.
|
|
129
141
|
if (subjectClasses.length || parts.length < 2) continue;
|
|
142
|
+
if (componentMode && parts.at(-1).combinator === '>') {
|
|
143
|
+
const types = subjectTypes(subject) ?? [];
|
|
144
|
+
for (const name of classNames(
|
|
145
|
+
withoutRelationalArguments(parts.at(-2).compound),
|
|
146
|
+
))
|
|
147
|
+
for (const type of types)
|
|
148
|
+
add(
|
|
149
|
+
composedChildren.get(`${name}|${type}`),
|
|
150
|
+
'descendant',
|
|
151
|
+
`.${name}`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
130
154
|
for (let index = parts.length - 2; index >= 0; index -= 1) {
|
|
131
155
|
const classes = classNames(
|
|
132
156
|
withoutRelationalArguments(parts[index].compound),
|
|
133
157
|
);
|
|
158
|
+
const hook = componentMode
|
|
159
|
+
? classes.find((name) => hooks.has(name))
|
|
160
|
+
: undefined;
|
|
161
|
+
if (hook) {
|
|
162
|
+
add(hooks.get(hook), 'descendant', `.${hook}`);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
134
165
|
if (classes.some((name) => !facts.classOwners.has(name))) break;
|
|
135
166
|
const anatomy = classes.find(
|
|
136
167
|
(name) => name.includes('__') && facts.classOwners.has(name),
|
|
@@ -139,6 +170,58 @@ export function restyledComponents(selectorList, facts, isForeign) {
|
|
|
139
170
|
add(facts.classOwners.get(anatomy), 'descendant', `.${anatomy}`);
|
|
140
171
|
break;
|
|
141
172
|
}
|
|
173
|
+
if (componentMode) {
|
|
174
|
+
const root = classes.find((name) => facts.classOwners.has(name));
|
|
175
|
+
if (root) {
|
|
176
|
+
const entry = facts.classOwners.get(root);
|
|
177
|
+
if (entry.package === ownPackage)
|
|
178
|
+
add(entry, 'descendant', `.${root}`);
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return found;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Same-package classes used to key another component's selector. */
|
|
188
|
+
export function contextualComponents(
|
|
189
|
+
selectorList,
|
|
190
|
+
facts,
|
|
191
|
+
isForeign,
|
|
192
|
+
ownPackage,
|
|
193
|
+
) {
|
|
194
|
+
const found = [];
|
|
195
|
+
const seen = new Set();
|
|
196
|
+
const selectorClasses = (text) => classNames(text.replace(/\[[^\]]*\]/g, ''));
|
|
197
|
+
for (const parts of complexSelectorParts(selectorList)) {
|
|
198
|
+
for (const [index, part] of parts.entries()) {
|
|
199
|
+
const compound = part.compound;
|
|
200
|
+
for (const name of selectorClasses(compound)) {
|
|
201
|
+
const entry = facts.classOwners.get(name);
|
|
202
|
+
if (!entry || entry.package !== ownPackage || !isForeign(entry))
|
|
203
|
+
continue;
|
|
204
|
+
const pseudo = ['has', 'is', 'where', 'not'].find((candidate) =>
|
|
205
|
+
pseudoArguments(compound, candidate).some((argument) =>
|
|
206
|
+
selectorClasses(argument).includes(name),
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
const position = pseudo
|
|
210
|
+
? pseudo
|
|
211
|
+
: index === parts.length - 1
|
|
212
|
+
? 'subject'
|
|
213
|
+
: ['+', '~'].includes(parts[index + 1].combinator)
|
|
214
|
+
? 'sibling'
|
|
215
|
+
: 'ancestor';
|
|
216
|
+
const key = `${entry.key}|${name}|${position}`;
|
|
217
|
+
if (seen.has(key)) continue;
|
|
218
|
+
seen.add(key);
|
|
219
|
+
found.push({
|
|
220
|
+
entry,
|
|
221
|
+
name: `.${name}`,
|
|
222
|
+
position,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
142
225
|
}
|
|
143
226
|
}
|
|
144
227
|
return found;
|
package/analyzer/index.d.mts
CHANGED
|
@@ -44,6 +44,8 @@ export function analyzeUiProject(options?: {
|
|
|
44
44
|
knownRules?: Iterable<string>;
|
|
45
45
|
adoption?: boolean;
|
|
46
46
|
ownership?: 'package' | 'component';
|
|
47
|
+
ownershipContext?: 'subject' | 'any';
|
|
48
|
+
implicitComponentOwnership?: boolean;
|
|
47
49
|
}): Promise<UiAnalysisReport>;
|
|
48
50
|
|
|
49
51
|
export function formatUiAnalysisText(report: UiAnalysisReport): string;
|