@nadicodeai/ui 6.0.2 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/action-menu.d.ts +8 -0
- package/dist/components/action-menu.d.ts.map +1 -0
- package/dist/components/action-menu.js +8 -0
- package/dist/components/card.d.ts +1 -1
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +5 -3
- package/dist/components/chart-breakdown-table.d.ts +3 -2
- package/dist/components/chart-breakdown-table.d.ts.map +1 -1
- package/dist/components/chart-breakdown-table.js +13 -9
- package/dist/components/chart-bullet-bar.d.ts +13 -12
- package/dist/components/chart-bullet-bar.d.ts.map +1 -1
- package/dist/components/chart-bullet-bar.js +16 -36
- package/dist/components/chart-kpi-stat.d.ts +26 -15
- package/dist/components/chart-kpi-stat.d.ts.map +1 -1
- package/dist/components/chart-kpi-stat.js +28 -4
- package/dist/components/chart-time-series-layout.d.ts +6 -0
- package/dist/components/chart-time-series-layout.d.ts.map +1 -0
- package/dist/components/chart-time-series-layout.js +6 -0
- package/dist/components/chart-time-series.d.ts +6 -2
- package/dist/components/chart-time-series.d.ts.map +1 -1
- package/dist/components/chart-time-series.js +27 -9
- package/dist/components/chart.js +1 -1
- package/dist/components/collection-filters.d.ts +28 -0
- package/dist/components/collection-filters.d.ts.map +1 -0
- package/dist/components/collection-filters.js +54 -0
- package/dist/components/collection-scope.d.ts +15 -0
- package/dist/components/collection-scope.d.ts.map +1 -0
- package/dist/components/collection-scope.js +7 -0
- package/dist/components/collection-toolbar.d.ts +10 -0
- package/dist/components/collection-toolbar.d.ts.map +1 -0
- package/dist/components/collection-toolbar.js +4 -0
- package/dist/components/forma-appearance.d.ts +13 -0
- package/dist/components/forma-appearance.d.ts.map +1 -0
- package/dist/components/forma-appearance.js +11 -0
- package/dist/components/settings-facts.d.ts +28 -0
- package/dist/components/settings-facts.d.ts.map +1 -0
- package/dist/components/settings-facts.js +7 -0
- package/dist/components/settings-section.d.ts +5 -5
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +6 -11
- package/dist/components/sidebar.d.ts +4 -1
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/components/sidebar.js +3 -3
- package/dist/components/table-layouts.d.ts +22 -0
- package/dist/components/table-layouts.d.ts.map +1 -0
- package/dist/components/table-layouts.js +20 -0
- package/dist/components/table.d.ts +15 -2
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +8 -4
- package/dist/eslint/rules/jsx-class-utility.js +44 -12
- package/dist/eslint/rules/no-resting-settings-control.js +15 -13
- package/dist/eslint/rules/no-shadcn-appearance-override.js +189 -36
- package/dist/eslint/rules/shadcn-composition.js +48 -3
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/internal/forma/stored-appearance.d.ts +29 -0
- package/dist/internal/forma/stored-appearance.d.ts.map +1 -0
- package/dist/internal/forma/stored-appearance.js +53 -0
- package/docs/component-classification.md +3 -2
- package/docs/contract.md +78 -7
- package/docs/forma-avatar.md +18 -0
- package/docs/product-compositions.md +14 -11
- package/package.json +3 -2
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* editor that changes them. The regression this catches is a form control
|
|
7
7
|
* rendered beside those facts rather than inside the editor they summon.
|
|
8
8
|
*
|
|
9
|
-
* "Inside the editor" means inside an `ActionDialogForm`'s
|
|
10
|
-
*
|
|
9
|
+
* "Inside the editor" means inside a `SettingsSection`, an `ActionDialogForm`'s
|
|
10
|
+
* `fields` prop, or a `Dialog`/`Drawer` subtree for a surface that owns its own. Being a
|
|
11
11
|
* CHILD of `ActionDialogForm` is the opposite: children are the resting surface
|
|
12
12
|
* the dialog is opened from, which is exactly where a control must not be.
|
|
13
13
|
*
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* here. Replaces `restingSettingsControlViolations` in the retired portal
|
|
22
22
|
* page-grammar analyzers (#821).
|
|
23
23
|
*/
|
|
24
|
+
import { jsxComponentName } from "./jsx-class-utility.js";
|
|
24
25
|
|
|
25
26
|
// The controls a person types or picks into. Lowercase `input` is deliberately
|
|
26
27
|
// absent: a hidden field carries context a summoned editor already decided, and
|
|
@@ -37,15 +38,15 @@ const RESTING_CONTROL_TAGS = new Set([
|
|
|
37
38
|
|
|
38
39
|
const FACTS_SECTION_TAG = "SettingsFactsSection";
|
|
39
40
|
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
function summons(node, context) {
|
|
42
|
+
if (node.type === "JSXAttribute") {
|
|
43
|
+
return (
|
|
44
|
+
node.name.name === "fields" && jsxComponentName(node.parent, context) === "ActionDialogForm"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
46
47
|
if (node.type !== "JSXElement") return false;
|
|
47
|
-
const name =
|
|
48
|
-
return
|
|
48
|
+
const name = jsxComponentName(node.openingElement, context);
|
|
49
|
+
return ["SettingsSection", "Dialog", "DialogContent", "Drawer", "DrawerContent"].includes(name);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export const noRestingSettingsControl = {
|
|
@@ -58,7 +59,7 @@ export const noRestingSettingsControl = {
|
|
|
58
59
|
schema: [],
|
|
59
60
|
messages: {
|
|
60
61
|
restingControl:
|
|
61
|
-
"<{{tag}}> rests beside its facts: put it in the editor
|
|
62
|
+
"<{{tag}}> rests beside its facts: use SettingsSection for a form, or put it in the summoned editor (ActionDialogForm `fields`, Dialog, or Drawer).",
|
|
62
63
|
},
|
|
63
64
|
},
|
|
64
65
|
create(context) {
|
|
@@ -67,13 +68,14 @@ export const noRestingSettingsControl = {
|
|
|
67
68
|
|
|
68
69
|
return {
|
|
69
70
|
JSXOpeningElement(node) {
|
|
70
|
-
const name =
|
|
71
|
+
const name = jsxComponentName(node, context);
|
|
71
72
|
if (name === FACTS_SECTION_TAG) {
|
|
72
73
|
declaresFacts = true;
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
75
76
|
if (!name || !RESTING_CONTROL_TAGS.has(name)) return;
|
|
76
|
-
if (context.sourceCode.getAncestors(node).some(summons))
|
|
77
|
+
if (context.sourceCode.getAncestors(node).some((ancestor) => summons(ancestor, context)))
|
|
78
|
+
return;
|
|
77
79
|
resting.push({ node, name });
|
|
78
80
|
},
|
|
79
81
|
"Program:exit"() {
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* of which still compile and still fork the primitive. Those are what survives
|
|
13
13
|
* here; the raw-palette names are gone from the sets below with the palette.
|
|
14
14
|
*/
|
|
15
|
+
import { posix } from "node:path";
|
|
16
|
+
|
|
15
17
|
import {
|
|
16
18
|
classUtilities,
|
|
17
19
|
openingElementClassUtilities,
|
|
@@ -19,6 +21,127 @@ import {
|
|
|
19
21
|
skipsPackageOwnedPrimitive,
|
|
20
22
|
} from "./jsx-class-utility.js";
|
|
21
23
|
|
|
24
|
+
// These exact Portal adapters forward props to package primitives. Card
|
|
25
|
+
// chooses its typed surface default; Table owns only structural geometry.
|
|
26
|
+
// Their other exports are direct reexports.
|
|
27
|
+
const portalCardExports = new Set([
|
|
28
|
+
"Card",
|
|
29
|
+
"CardHeader",
|
|
30
|
+
"CardTitle",
|
|
31
|
+
"CardDescription",
|
|
32
|
+
"CardAction",
|
|
33
|
+
"CardContent",
|
|
34
|
+
]);
|
|
35
|
+
const portalTableExports = new Set([
|
|
36
|
+
"Table",
|
|
37
|
+
"TableHead",
|
|
38
|
+
"TableCell",
|
|
39
|
+
"TableBody",
|
|
40
|
+
"TableCaption",
|
|
41
|
+
"TableFooter",
|
|
42
|
+
"TableHeader",
|
|
43
|
+
"TableRow",
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
function primitiveModule(source, filename) {
|
|
47
|
+
if (source.startsWith("@nadicodeai/ui/components/")) {
|
|
48
|
+
return { card: source === "@nadicodeai/ui/components/card", exports: undefined };
|
|
49
|
+
}
|
|
50
|
+
const normalized = filename.replaceAll("\\", "/");
|
|
51
|
+
const portalStart = normalized.lastIndexOf("/apps/portal/src/");
|
|
52
|
+
if (portalStart === -1) return undefined;
|
|
53
|
+
const portalSource = `${normalized.slice(0, portalStart)}/apps/portal/src`;
|
|
54
|
+
const resolved = source.startsWith(".")
|
|
55
|
+
? posix.normalize(posix.join(posix.dirname(normalized), source)).replace(/\.[jt]sx?$/, "")
|
|
56
|
+
: undefined;
|
|
57
|
+
if (source === "@/components/kit/card" || resolved === `${portalSource}/components/kit/card`) {
|
|
58
|
+
return { card: true, exports: portalCardExports };
|
|
59
|
+
}
|
|
60
|
+
if (source === "@/components/kit/table" || resolved === `${portalSource}/components/kit/table`) {
|
|
61
|
+
return { card: false, exports: portalTableExports };
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function primitiveExport(module, name) {
|
|
67
|
+
if (module.exports && !module.exports.has(name)) return undefined;
|
|
68
|
+
return { cardRoot: module.card && name === "Card" };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const appearanceStyleProperties = new Set([
|
|
72
|
+
"appearance",
|
|
73
|
+
"WebkitAppearance",
|
|
74
|
+
"MozAppearance",
|
|
75
|
+
"color",
|
|
76
|
+
"background",
|
|
77
|
+
"backgroundColor",
|
|
78
|
+
"backgroundImage",
|
|
79
|
+
"boxShadow",
|
|
80
|
+
"textShadow",
|
|
81
|
+
"opacity",
|
|
82
|
+
"outlineColor",
|
|
83
|
+
"filter",
|
|
84
|
+
"backdropFilter",
|
|
85
|
+
"WebkitBackdropFilter",
|
|
86
|
+
"fill",
|
|
87
|
+
"fillOpacity",
|
|
88
|
+
"stroke",
|
|
89
|
+
"strokeOpacity",
|
|
90
|
+
...[
|
|
91
|
+
"",
|
|
92
|
+
"Top",
|
|
93
|
+
"Right",
|
|
94
|
+
"Bottom",
|
|
95
|
+
"Left",
|
|
96
|
+
"Block",
|
|
97
|
+
"Inline",
|
|
98
|
+
"BlockStart",
|
|
99
|
+
"BlockEnd",
|
|
100
|
+
"InlineStart",
|
|
101
|
+
"InlineEnd",
|
|
102
|
+
].map((side) => `border${side}Color`),
|
|
103
|
+
...[
|
|
104
|
+
"",
|
|
105
|
+
"TopLeft",
|
|
106
|
+
"TopRight",
|
|
107
|
+
"BottomLeft",
|
|
108
|
+
"BottomRight",
|
|
109
|
+
"StartStart",
|
|
110
|
+
"StartEnd",
|
|
111
|
+
"EndStart",
|
|
112
|
+
"EndEnd",
|
|
113
|
+
].map((corner) => `border${corner}Radius`),
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
function staticStyleValue(node) {
|
|
117
|
+
if (node.type === "Literal") return node.value;
|
|
118
|
+
if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
|
|
119
|
+
return node.quasis[0]?.value.cooked;
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Inline object literals only. Unknown values, computed keys, imported style
|
|
125
|
+
// objects and spreads remain review work; layout properties are not paint.
|
|
126
|
+
function inlineAppearanceProperties(attribute) {
|
|
127
|
+
if (attribute.type !== "JSXAttribute" || attribute.name.name !== "style") return [];
|
|
128
|
+
const expression =
|
|
129
|
+
attribute.value?.type === "JSXExpressionContainer" ? attribute.value.expression : undefined;
|
|
130
|
+
if (expression?.type !== "ObjectExpression") return [];
|
|
131
|
+
return expression.properties.filter((property) => {
|
|
132
|
+
if (property.type !== "Property") return false;
|
|
133
|
+
const name =
|
|
134
|
+
property.key.type === "Literal"
|
|
135
|
+
? property.key.value
|
|
136
|
+
: !property.computed && property.key.type === "Identifier"
|
|
137
|
+
? property.key.name
|
|
138
|
+
: undefined;
|
|
139
|
+
if (!appearanceStyleProperties.has(name)) return false;
|
|
140
|
+
const value = staticStyleValue(property.value);
|
|
141
|
+
return typeof value === "number" || (typeof value === "string" && value.trim() !== "");
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
22
145
|
function withoutVariants(utility) {
|
|
23
146
|
return utility.slice(utility.lastIndexOf(":") + 1);
|
|
24
147
|
}
|
|
@@ -74,7 +197,10 @@ function isAppearanceUtility(utility) {
|
|
|
74
197
|
|
|
75
198
|
function isProhibitedAppearanceUtility(utility, { cardRoot = false } = {}) {
|
|
76
199
|
const base = withoutVariants(utility);
|
|
77
|
-
return
|
|
200
|
+
return (
|
|
201
|
+
targetsSharedSlot(utility) ||
|
|
202
|
+
(isAppearanceUtility(utility) && (!isBorderRemoval(base) || cardRoot))
|
|
203
|
+
);
|
|
78
204
|
}
|
|
79
205
|
|
|
80
206
|
function targetsSharedSlot(utility) {
|
|
@@ -92,15 +218,14 @@ export const noShadcnAppearanceOverride = {
|
|
|
92
218
|
meta: {
|
|
93
219
|
type: "problem",
|
|
94
220
|
docs: {
|
|
95
|
-
description:
|
|
96
|
-
"Disallow app callers repainting imported shadcn primitives; compose their structural layout only",
|
|
221
|
+
description: "Keep shared component appearance and internal slot layout at their owner",
|
|
97
222
|
},
|
|
98
223
|
// Default "exempt": inside @nadicodeai/ui the primitives ARE the appearance,
|
|
99
224
|
// so every utility here would be a false positive.
|
|
100
225
|
schema: [packageOwnedPrimitivesSchema],
|
|
101
226
|
messages: {
|
|
102
227
|
appearanceOverride:
|
|
103
|
-
"Do not
|
|
228
|
+
"Do not override shared component appearance or internal slot layout with {{utility}}; use a component prop or fix its shared owner.",
|
|
104
229
|
},
|
|
105
230
|
},
|
|
106
231
|
create(context) {
|
|
@@ -108,48 +233,76 @@ export const noShadcnAppearanceOverride = {
|
|
|
108
233
|
return {};
|
|
109
234
|
}
|
|
110
235
|
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
236
|
+
const sourceCode = context.sourceCode;
|
|
237
|
+
const sharedBindings = new Map();
|
|
238
|
+
|
|
239
|
+
function importedBinding(identifier) {
|
|
240
|
+
for (let scope = sourceCode.getScope(identifier); scope; scope = scope.upper) {
|
|
241
|
+
const variable = scope.set.get(identifier.name);
|
|
242
|
+
if (variable) return sharedBindings.get(variable);
|
|
243
|
+
}
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function sharedPrimitive(node) {
|
|
248
|
+
if (node?.type !== "JSXOpeningElement") return undefined;
|
|
249
|
+
if (node.name.type === "JSXIdentifier") {
|
|
250
|
+
const binding = importedBinding(node.name);
|
|
251
|
+
return binding && binding.name !== "*"
|
|
252
|
+
? primitiveExport(binding.module, binding.name)
|
|
253
|
+
: undefined;
|
|
254
|
+
}
|
|
255
|
+
if (node.name.type === "JSXMemberExpression" && node.name.object.type === "JSXIdentifier") {
|
|
256
|
+
const binding = importedBinding(node.name.object);
|
|
257
|
+
return binding?.name === "*"
|
|
258
|
+
? primitiveExport(binding.module, node.name.property.name)
|
|
259
|
+
: undefined;
|
|
260
|
+
}
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
121
264
|
return {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
265
|
+
Program(node) {
|
|
266
|
+
// Imports are hoisted; collect their declared variables before visiting
|
|
267
|
+
// JSX. Binding identity also distinguishes shadowing parameters/locals.
|
|
268
|
+
for (const declaration of node.body) {
|
|
269
|
+
if (declaration.type !== "ImportDeclaration" || declaration.importKind === "type")
|
|
270
|
+
continue;
|
|
271
|
+
const module = primitiveModule(declaration.source.value, context.filename);
|
|
272
|
+
if (!module) continue;
|
|
273
|
+
for (const specifier of declaration.specifiers) {
|
|
274
|
+
if (specifier.importKind === "type") continue;
|
|
275
|
+
const name =
|
|
276
|
+
specifier.type === "ImportNamespaceSpecifier"
|
|
277
|
+
? "*"
|
|
278
|
+
: specifier.type === "ImportSpecifier"
|
|
279
|
+
? (specifier.imported.name ?? specifier.imported.value)
|
|
280
|
+
: "default";
|
|
281
|
+
for (const variable of sourceCode.getDeclaredVariables(specifier)) {
|
|
282
|
+
sharedBindings.set(variable, { module, name });
|
|
283
|
+
}
|
|
137
284
|
}
|
|
138
285
|
}
|
|
139
286
|
},
|
|
140
287
|
JSXOpeningElement(node) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
isProhibitedAppearanceUtility(utility, { cardRoot: isSharedCardRoot(node) })
|
|
146
|
-
) {
|
|
288
|
+
const primitive = sharedPrimitive(node);
|
|
289
|
+
if (!primitive) return;
|
|
290
|
+
for (const utility of openingElementClassUtilities(node, context, true)) {
|
|
291
|
+
if (utility && isProhibitedAppearanceUtility(utility, primitive)) {
|
|
147
292
|
context.report({ node, messageId: "appearanceOverride", data: { utility } });
|
|
148
293
|
}
|
|
149
294
|
}
|
|
295
|
+
for (const property of node.attributes.flatMap(inlineAppearanceProperties)) {
|
|
296
|
+
const name = property.key.name ?? property.key.value;
|
|
297
|
+
context.report({
|
|
298
|
+
node: property,
|
|
299
|
+
messageId: "appearanceOverride",
|
|
300
|
+
data: { utility: `style.${name}` },
|
|
301
|
+
});
|
|
302
|
+
}
|
|
150
303
|
},
|
|
151
304
|
JSXAttribute(node) {
|
|
152
|
-
if (
|
|
305
|
+
if (sharedPrimitive(node.parent)) return;
|
|
153
306
|
for (const utility of classUtilities(node, context)) {
|
|
154
307
|
if (
|
|
155
308
|
!targetsSharedSlot(utility) ||
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* The
|
|
2
|
+
* The composition conventions the shared components are built to, checked
|
|
3
3
|
* where they are composed:
|
|
4
4
|
*
|
|
5
5
|
* - an overlay carries its title, so a screen reader announces what opened
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* - an `AvatarImage` has an `AvatarFallback` beside it, or the avatar is blank
|
|
10
10
|
* until the image loads;
|
|
11
11
|
* - a lucide icon inside a `Button` carries `data-icon`, the hook the button's
|
|
12
|
-
* own spacing rules key on
|
|
12
|
+
* own spacing rules key on;
|
|
13
|
+
* - a settings submit action uses SettingsSection's shared footer, so each
|
|
14
|
+
* caller cannot rebuild its own divider, padding, and action position.
|
|
13
15
|
*
|
|
14
16
|
* Standard tool checked first: `jsx-a11y` covers roles and ARIA on
|
|
15
17
|
* intrinsic elements and says nothing about these composed components;
|
|
@@ -18,7 +20,11 @@
|
|
|
18
20
|
* of the retired @nadicodeai/ui composition-conventions scanner (#822); stock
|
|
19
21
|
* upstream shapes carry an inline disable with the reason at the site.
|
|
20
22
|
*/
|
|
21
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
jsxComponentName,
|
|
25
|
+
packageOwnedPrimitivesSchema,
|
|
26
|
+
skipsPackageOwnedPrimitive,
|
|
27
|
+
} from "./jsx-class-utility.js";
|
|
22
28
|
|
|
23
29
|
const OVERLAY_TITLES = {
|
|
24
30
|
AlertDialogContent: "AlertDialogTitle",
|
|
@@ -75,6 +81,39 @@ function isIconTag(tagName) {
|
|
|
75
81
|
return tagName === "Icon" || tagName.endsWith("Icon");
|
|
76
82
|
}
|
|
77
83
|
|
|
84
|
+
function misplacedSettingsSubmit(node, context) {
|
|
85
|
+
if (jsxComponentName(node, context) !== "Button") return false;
|
|
86
|
+
const attribute = node.attributes.find(
|
|
87
|
+
(entry) => entry.type === "JSXAttribute" && entry.name.name === "type",
|
|
88
|
+
);
|
|
89
|
+
const value =
|
|
90
|
+
attribute?.value?.type === "JSXExpressionContainer"
|
|
91
|
+
? attribute.value.expression
|
|
92
|
+
: attribute?.value;
|
|
93
|
+
const type =
|
|
94
|
+
value?.type === "TemplateLiteral" && value.expressions.length === 0
|
|
95
|
+
? value.quasis[0]?.value.cooked
|
|
96
|
+
: value?.value;
|
|
97
|
+
if (type !== "submit") return false;
|
|
98
|
+
const ancestors = context.sourceCode.getAncestors(node);
|
|
99
|
+
const section = ancestors.findLast(
|
|
100
|
+
(ancestor) =>
|
|
101
|
+
ancestor.type === "JSXElement" &&
|
|
102
|
+
jsxComponentName(ancestor.openingElement, context) === "SettingsSection",
|
|
103
|
+
);
|
|
104
|
+
if (!section) return false;
|
|
105
|
+
return !ancestors.slice(ancestors.indexOf(section) + 1).some((ancestor) => {
|
|
106
|
+
if (ancestor.type === "JSXAttribute")
|
|
107
|
+
return ancestor.name.name === "footer" && ancestor.parent === section.openingElement;
|
|
108
|
+
return (
|
|
109
|
+
ancestor.type === "JSXElement" &&
|
|
110
|
+
["DialogContent", "DrawerContent", "AlertDialogContent"].includes(
|
|
111
|
+
jsxComponentName(ancestor.openingElement, context),
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
78
117
|
export const shadcnComposition = {
|
|
79
118
|
meta: {
|
|
80
119
|
type: "problem",
|
|
@@ -88,6 +127,8 @@ export const shadcnComposition = {
|
|
|
88
127
|
selectGroup: "SelectItem must be rendered inside SelectGroup.",
|
|
89
128
|
avatarFallback: "AvatarImage requires an AvatarFallback in the same Avatar.",
|
|
90
129
|
buttonIcon: "An icon inside Button must carry data-icon.",
|
|
130
|
+
settingsFooter:
|
|
131
|
+
"Put a SettingsSection submit action in its footer prop; the shared component owns the divider, spacing, and action position.",
|
|
91
132
|
},
|
|
92
133
|
},
|
|
93
134
|
create(context) {
|
|
@@ -101,6 +142,10 @@ export const shadcnComposition = {
|
|
|
101
142
|
if (!tag) return;
|
|
102
143
|
const element = node.parent;
|
|
103
144
|
|
|
145
|
+
if (misplacedSettingsSubmit(node, context)) {
|
|
146
|
+
context.report({ node, messageId: "settingsFooter" });
|
|
147
|
+
}
|
|
148
|
+
|
|
104
149
|
const title = OVERLAY_TITLES[tag];
|
|
105
150
|
if (title && !hasDescendant(element, title)) {
|
|
106
151
|
context.report({ node, messageId: "overlayTitle", data: { tag, title } });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./components/accordion.js";
|
|
2
2
|
export * from "./components/action-band.js";
|
|
3
|
+
export * from "./components/action-menu.js";
|
|
3
4
|
export * from "./components/action-status.js";
|
|
4
5
|
export * from "./components/activity-orb.js";
|
|
5
6
|
export * from "./components/alert.js";
|
|
@@ -20,6 +21,7 @@ export * from "./components/button.js";
|
|
|
20
21
|
export * from "./components/button-group.js";
|
|
21
22
|
export * from "./components/calendar.js";
|
|
22
23
|
export * from "./components/card.js";
|
|
24
|
+
export * from "./components/collection-scope.js";
|
|
23
25
|
export * from "./components/card-marketing.js";
|
|
24
26
|
export * from "./components/carousel.js";
|
|
25
27
|
export * from "./components/chart.js";
|
|
@@ -105,6 +107,9 @@ export * from "./components/security-grid.js";
|
|
|
105
107
|
export * from "./components/select.js";
|
|
106
108
|
export * from "./components/separator.js";
|
|
107
109
|
export * from "./components/settings-section.js";
|
|
110
|
+
export * from "./components/settings-facts.js";
|
|
111
|
+
export * from "./components/collection-toolbar.js";
|
|
112
|
+
export * from "./components/collection-filters.js";
|
|
108
113
|
export * from "./components/sheet.js";
|
|
109
114
|
export * from "./components/shift-band.js";
|
|
110
115
|
export * from "./components/sidebar.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./components/accordion.js";
|
|
2
2
|
export * from "./components/action-band.js";
|
|
3
|
+
export * from "./components/action-menu.js";
|
|
3
4
|
export * from "./components/action-status.js";
|
|
4
5
|
export * from "./components/activity-orb.js";
|
|
5
6
|
export * from "./components/alert.js";
|
|
@@ -20,6 +21,7 @@ export * from "./components/button.js";
|
|
|
20
21
|
export * from "./components/button-group.js";
|
|
21
22
|
export * from "./components/calendar.js";
|
|
22
23
|
export * from "./components/card.js";
|
|
24
|
+
export * from "./components/collection-scope.js";
|
|
23
25
|
export * from "./components/card-marketing.js";
|
|
24
26
|
export * from "./components/carousel.js";
|
|
25
27
|
export * from "./components/chart.js";
|
|
@@ -105,6 +107,9 @@ export * from "./components/security-grid.js";
|
|
|
105
107
|
export * from "./components/select.js";
|
|
106
108
|
export * from "./components/separator.js";
|
|
107
109
|
export * from "./components/settings-section.js";
|
|
110
|
+
export * from "./components/settings-facts.js";
|
|
111
|
+
export * from "./components/collection-toolbar.js";
|
|
112
|
+
export * from "./components/collection-filters.js";
|
|
108
113
|
export * from "./components/sheet.js";
|
|
109
114
|
export * from "./components/shift-band.js";
|
|
110
115
|
export * from "./components/sidebar.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type FormaChoice, type FormaColor } from "./model.js";
|
|
2
|
+
/** What Hermes stores for an Agent's look. Both may be absent or unknown. */
|
|
3
|
+
export interface StoredAppearance {
|
|
4
|
+
shape?: string | null;
|
|
5
|
+
color?: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** The `shape` value a chosen form is stored as. */
|
|
8
|
+
export declare const shapeFor: (form: FormaChoice) => string;
|
|
9
|
+
/** The stored shape of the form an Agent wears until a customer chooses one. */
|
|
10
|
+
export declare const defaultShape: string;
|
|
11
|
+
/**
|
|
12
|
+
* The hex each palette colour is stored as. Hermes keeps an Agent's colour as
|
|
13
|
+
* a CSS colour for its own surfaces, so the stored spelling is a value rather
|
|
14
|
+
* than a token reference; `stored-appearance.test.ts` holds this table to the
|
|
15
|
+
* shipped design-system tokens, and the ESLint colour-literal exemption in the
|
|
16
|
+
* root config names this file.
|
|
17
|
+
*/
|
|
18
|
+
export declare const formaColorValues: Record<FormaColor, string>;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the stored strings to what `FormaAvatar` draws. An unknown shape is
|
|
21
|
+
* the default form and an unknown colour is undefined, which leaves the form
|
|
22
|
+
* its own pigment. The root Agent is the caller's business: a caller that owns
|
|
23
|
+
* one passes `form="nadia"` instead of asking here.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveAppearance(stored: StoredAppearance): {
|
|
26
|
+
form: FormaChoice;
|
|
27
|
+
color: FormaColor | undefined;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=stored-appearance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stored-appearance.d.ts","sourceRoot":"","sources":["../../../src/internal/forma/stored-appearance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAA0C,MAAM,SAAS,CAAC;AAEpG,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,oDAAoD;AACpD,eAAO,MAAM,QAAQ,GAAI,MAAM,WAAW,KAAG,MAAyB,CAAC;AAEvE,gFAAgF;AAChF,eAAO,MAAM,YAAY,EAAE,MAA8B,CAAC;AAc1D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOvD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG;IAC3D,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;CAC/B,CAEA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defaultForm, formaChoices, formaColors } from "./model.js";
|
|
2
|
+
/** The `shape` value a chosen form is stored as. */
|
|
3
|
+
export const shapeFor = (form) => `forma:${form}`;
|
|
4
|
+
/** The stored shape of the form an Agent wears until a customer chooses one. */
|
|
5
|
+
export const defaultShape = shapeFor(defaultForm);
|
|
6
|
+
/**
|
|
7
|
+
* The five role names the launch Agents were stored under, each kept at the
|
|
8
|
+
* form it wore. Forms are shapes, never roles: nothing new is stored this way.
|
|
9
|
+
*/
|
|
10
|
+
const legacyShapes = new Map([
|
|
11
|
+
["forma:research", "uovo"],
|
|
12
|
+
["forma:build", "goccia"],
|
|
13
|
+
["forma:design", "nuvola"],
|
|
14
|
+
["forma:operate", "quadrato"],
|
|
15
|
+
["forma:review", "esagono"],
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* The hex each palette colour is stored as. Hermes keeps an Agent's colour as
|
|
19
|
+
* a CSS colour for its own surfaces, so the stored spelling is a value rather
|
|
20
|
+
* than a token reference; `stored-appearance.test.ts` holds this table to the
|
|
21
|
+
* shipped design-system tokens, and the ESLint colour-literal exemption in the
|
|
22
|
+
* root config names this file.
|
|
23
|
+
*/
|
|
24
|
+
export const formaColorValues = {
|
|
25
|
+
verde: "#00a85a",
|
|
26
|
+
cobalto: "#1e3cff",
|
|
27
|
+
rosso: "#d3302f",
|
|
28
|
+
arancio: "#ff5a1f",
|
|
29
|
+
giallo: "#ffc220",
|
|
30
|
+
avorio: "#e9e7db",
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the stored strings to what `FormaAvatar` draws. An unknown shape is
|
|
34
|
+
* the default form and an unknown colour is undefined, which leaves the form
|
|
35
|
+
* its own pigment. The root Agent is the caller's business: a caller that owns
|
|
36
|
+
* one passes `form="nadia"` instead of asking here.
|
|
37
|
+
*/
|
|
38
|
+
export function resolveAppearance(stored) {
|
|
39
|
+
return { form: formFor(stored.shape), color: colorFor(stored.color) };
|
|
40
|
+
}
|
|
41
|
+
function formFor(shape) {
|
|
42
|
+
if (!shape)
|
|
43
|
+
return defaultForm;
|
|
44
|
+
// A Map, not an object: the shape is a stored string from a machine, and an
|
|
45
|
+
// object lookup would hand back `toString` or `constructor` for those spellings.
|
|
46
|
+
return (formaChoices.find((form) => shape === shapeFor(form)) ?? legacyShapes.get(shape) ?? defaultForm);
|
|
47
|
+
}
|
|
48
|
+
function colorFor(color) {
|
|
49
|
+
if (!color)
|
|
50
|
+
return undefined;
|
|
51
|
+
const stored = color.toLowerCase();
|
|
52
|
+
return formaColors.find((name) => stored === formaColorValues[name] || color === name);
|
|
53
|
+
}
|
|
@@ -19,8 +19,9 @@ copy, and behavior.
|
|
|
19
19
|
|
|
20
20
|
| Component | Classification | Built on | Required states | Package-owned accessibility | Fixture |
|
|
21
21
|
| --- | --- | --- | --- | --- | --- |
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
22
|
+
| `ActionMenu` | Canonical record-action composition. | shadcn `Button` and `DropdownMenu`. | closed, open, keyboard selection, focus return. | Required accessible trigger name; inherited menu mechanics. | `../src/components/action-menu.test.tsx` |
|
|
23
|
+
| `SettingsSection` | NadicodeAI product composition. | shadcn Card slots, Separator, and FieldGroup. | header, field group, and divided action footer. | Section structure; consumer owns the form transaction. | `../src/components/settings-section.test.tsx` |
|
|
24
|
+
| `SettingsField` | NadicodeAI product composition. | shadcn Field, FieldLabel, FieldDescription, and FieldError. | valid, invalid, required, and disabled field rows. | Render callback supplies the control's label and message associations in server and client components. | `../src/components/settings-section.test.tsx` |
|
|
24
25
|
| `FeedbackState` | Net-new central product state composition adapted from shadcn empty-state patterns. | shadcn `Empty` and lucide status icons. | `empty`, `loading`, `saving`, `error`, `permission`, `offline`, `no-results`, `fatal`. | `role="status"` for loading/saving; `role="alert"` for error, permission, offline, and fatal. | `../tests/guards/product-compositions.test.ts` |
|
|
25
26
|
|
|
26
27
|
## App-Owned Boundaries
|