@adea-ai/ui 0.77.0 → 0.78.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.
@@ -0,0 +1,34 @@
1
+ type Json = string | number | boolean | null | Json[] | {
2
+ [key: string]: Json;
3
+ };
4
+ type RuleModule = {
5
+ meta: {
6
+ type: 'problem';
7
+ docs: {
8
+ description: string;
9
+ };
10
+ schema: Json[];
11
+ messages: Record<string, string>;
12
+ };
13
+ create: (context: LintContext) => Record<string, (node: any) => void>;
14
+ };
15
+ interface LintContext {
16
+ options?: unknown[];
17
+ report: (descriptor: {
18
+ node: unknown;
19
+ messageId?: string;
20
+ message?: string;
21
+ data?: Record<string, Json>;
22
+ }) => void;
23
+ }
24
+ declare const plugin: {
25
+ meta: {
26
+ name: string;
27
+ };
28
+ rules: {
29
+ 'no-raw-interactive-elements': RuleModule;
30
+ 'no-primitive-library-imports': RuleModule;
31
+ };
32
+ };
33
+ export default plugin;
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint/index.ts"],"names":[],"mappings":"AAmBA,KAAK,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAA;AAa/E,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS,CAAA;QACf,IAAI,EAAE;YAAE,WAAW,EAAE,MAAM,CAAA;SAAE,CAAA;QAC7B,MAAM,EAAE,IAAI,EAAE,CAAA;QACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACjC,CAAA;IACD,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC,CAAA;CACtE,CAAA;AAED,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAA;IACnB,MAAM,EAAE,CAAC,UAAU,EAAE;QACnB,IAAI,EAAE,OAAO,CAAA;QACb,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;KAC5B,KAAK,IAAI,CAAA;CACX;AAwHD,QAAA,MAAM,MAAM;;;;;;;;CAMX,CAAA;AAED,eAAe,MAAM,CAAA"}
package/dist/lint.js ADDED
@@ -0,0 +1,130 @@
1
+ //#region src/lint/index.ts
2
+ /** The raw elements this package replaces, and the primitive that replaces them. */
3
+ var ELEMENT_PRIMITIVES = Object.freeze({
4
+ button: {
5
+ primitive: "Button",
6
+ path: "@adea-ai/ui/components/ui/button"
7
+ },
8
+ input: {
9
+ primitive: "Input",
10
+ path: "@adea-ai/ui/components/ui/input"
11
+ },
12
+ textarea: {
13
+ primitive: "Textarea",
14
+ path: "@adea-ai/ui/components/ui/textarea"
15
+ },
16
+ select: {
17
+ primitive: "Select",
18
+ path: "@adea-ai/ui/components/ui/select"
19
+ },
20
+ option: {
21
+ primitive: "Select",
22
+ path: "@adea-ai/ui/components/ui/select"
23
+ },
24
+ label: {
25
+ primitive: "Label",
26
+ path: "@adea-ai/ui/components/ui/label"
27
+ }
28
+ });
29
+ var noRawInteractiveElements = {
30
+ meta: {
31
+ type: "problem",
32
+ docs: { description: "Interactive elements this package provides (button, input, textarea, select, option, label) are composed from the package, not written as raw markup." },
33
+ schema: [{
34
+ type: "object",
35
+ properties: {
36
+ allow: {
37
+ type: "array",
38
+ items: { type: "string" }
39
+ },
40
+ message: { type: "string" }
41
+ },
42
+ additionalProperties: false
43
+ }],
44
+ messages: { rawElement: "{{element}} is provided by the design system: use {{primitive}} from {{path}}. A raw element has no keyboard story, no focus behaviour and no token styling — that is the work the primitive already did." }
45
+ },
46
+ create(context) {
47
+ const options = context.options?.[0] ?? {};
48
+ const allowed = new Set(options.allow ?? []);
49
+ const emit = (node, element) => {
50
+ const target = ELEMENT_PRIMITIVES[element];
51
+ context.report({
52
+ node,
53
+ messageId: "rawElement",
54
+ data: {
55
+ element,
56
+ primitive: target.primitive,
57
+ path: target.path
58
+ },
59
+ ...options.message ? { message: options.message } : {}
60
+ });
61
+ };
62
+ return { JSXOpeningElement(node) {
63
+ if (node.name?.type !== "JSXIdentifier") return;
64
+ const element = node.name.name;
65
+ if (!(element in ELEMENT_PRIMITIVES) || allowed.has(element)) return;
66
+ emit(node, element);
67
+ } };
68
+ }
69
+ };
70
+ var DEFAULT_PRIMITIVE_PACKAGES = Object.freeze([
71
+ "@kobalte/core",
72
+ "@ark-ui",
73
+ "@zag-js",
74
+ "@radix-ui",
75
+ "radix-ui",
76
+ "@base-ui-components"
77
+ ]);
78
+ var plugin = {
79
+ meta: { name: "adea" },
80
+ rules: {
81
+ "no-raw-interactive-elements": noRawInteractiveElements,
82
+ "no-primitive-library-imports": {
83
+ meta: {
84
+ type: "problem",
85
+ docs: { description: "The primitive libraries the design system is built on (Kobalte and friends) are its internal affair — compose the exported components instead of importing the primitives." },
86
+ schema: [{
87
+ type: "object",
88
+ properties: {
89
+ packages: {
90
+ type: "array",
91
+ items: { type: "string" }
92
+ },
93
+ message: { type: "string" }
94
+ },
95
+ additionalProperties: false
96
+ }],
97
+ messages: { primitiveImport: "Import from the design system, not from {{package}}: the primitives it wraps carry the focus, keyboard and ARIA behaviour the components exist to provide." }
98
+ },
99
+ create(context) {
100
+ const options = context.options?.[0] ?? {};
101
+ const prefixes = options.packages ?? DEFAULT_PRIMITIVE_PACKAGES;
102
+ const offender = (source) => {
103
+ const name = String(source ?? "");
104
+ return prefixes.find((prefix) => name === prefix || name.startsWith(`${prefix}/`)) ?? null;
105
+ };
106
+ const report = (node, source) => {
107
+ const pkg = offender(source);
108
+ context.report({
109
+ node,
110
+ messageId: "primitiveImport",
111
+ data: { package: pkg },
112
+ ...options.message ? { message: options.message } : {}
113
+ });
114
+ };
115
+ return {
116
+ ImportDeclaration(node) {
117
+ if (offender(node.source?.value)) report(node, node.source.value);
118
+ },
119
+ ImportExpression(node) {
120
+ if (typeof node.source?.value === "string" && offender(node.source.value)) report(node, node.source.value);
121
+ }
122
+ };
123
+ }
124
+ }
125
+ }
126
+ };
127
+ //#endregion
128
+ export { plugin as default };
129
+
130
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","names":[],"sources":["../src/lint/index.ts"],"sourcesContent":["/*\n * The design system's own oxlint plugin.\n *\n * The styling rules live in `@shadcn/lint`; what that plugin cannot know is which\n * *elements* the design system owns. This is the other half of the contract, for\n * the applications that consume the library: an interactive element this package\n * provides is not re-implemented at the application layer, and the primitive\n * libraries this package is built from are not imported around it.\n *\n * Loaded as an oxlint jsPlugin:\n *\n * // .oxlintrc.json\n * { \"jsPlugins\": [\"@adea-ai/ui/lint\"], \"rules\": { \"adea/no-raw-interactive-elements\": \"error\" } }\n *\n * Rules are errors by intent. A violation means an application composed its own\n * control out of raw markup — unreachable focus behaviour, an absent keyboard\n * story, a second implementation of a decision this package exists to make once.\n */\n\ntype Json = string | number | boolean | null | Json[] | { [key: string]: Json }\n\n/** The raw elements this package replaces, and the primitive that replaces them. */\nconst ELEMENT_PRIMITIVES: Readonly<Record<string, { primitive: string; path: string }>> =\n Object.freeze({\n button: { primitive: 'Button', path: '@adea-ai/ui/components/ui/button' },\n input: { primitive: 'Input', path: '@adea-ai/ui/components/ui/input' },\n textarea: { primitive: 'Textarea', path: '@adea-ai/ui/components/ui/textarea' },\n select: { primitive: 'Select', path: '@adea-ai/ui/components/ui/select' },\n option: { primitive: 'Select', path: '@adea-ai/ui/components/ui/select' },\n label: { primitive: 'Label', path: '@adea-ai/ui/components/ui/label' },\n })\n\ntype RuleModule = {\n meta: {\n type: 'problem'\n docs: { description: string }\n schema: Json[]\n messages: Record<string, string>\n }\n create: (context: LintContext) => Record<string, (node: any) => void>\n}\n\ninterface LintContext {\n options?: unknown[]\n report: (descriptor: {\n node: unknown\n messageId?: string\n message?: string\n data?: Record<string, Json>\n }) => void\n}\n\ninterface RawElementOptions {\n /** Element names this rule should not report (rare; prefer fixing the file). */\n allow?: string[]\n /** Replaces the default report message. */\n message?: string\n}\n\nconst noRawInteractiveElements: RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Interactive elements this package provides (button, input, textarea, select, option, label) are composed from the package, not written as raw markup.',\n },\n schema: [\n {\n type: 'object',\n properties: {\n allow: { type: 'array', items: { type: 'string' } },\n message: { type: 'string' },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n rawElement:\n '{{element}} is provided by the design system: use {{primitive}} from {{path}}. A raw element has no keyboard story, no focus behaviour and no token styling — that is the work the primitive already did.',\n },\n },\n create(context) {\n const options = (context.options?.[0] ?? {}) as RawElementOptions\n const allowed = new Set(options.allow ?? [])\n const emit = (node: unknown, element: string) => {\n const target = ELEMENT_PRIMITIVES[element]!\n context.report({\n node,\n messageId: 'rawElement',\n data: { element, primitive: target.primitive, path: target.path },\n ...(options.message ? { message: options.message } : {}),\n })\n }\n return {\n JSXOpeningElement(node: any) {\n if (node.name?.type !== 'JSXIdentifier') return\n const element = node.name.name\n if (!(element in ELEMENT_PRIMITIVES) || allowed.has(element)) return\n emit(node, element)\n },\n }\n },\n}\n\ninterface PrimitiveImportOptions {\n /** Package prefixes this rule reports. Defaults to the primitive libraries the ui package wraps. */\n packages?: string[]\n /** Replaces the default report message. */\n message?: string\n}\n\nconst DEFAULT_PRIMITIVE_PACKAGES = Object.freeze([\n '@kobalte/core',\n '@ark-ui',\n '@zag-js',\n '@radix-ui',\n 'radix-ui',\n '@base-ui-components',\n])\n\nconst noPrimitiveLibraryImports: RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'The primitive libraries the design system is built on (Kobalte and friends) are its internal affair — compose the exported components instead of importing the primitives.',\n },\n schema: [\n {\n type: 'object',\n properties: {\n packages: { type: 'array', items: { type: 'string' } },\n message: { type: 'string' },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n primitiveImport:\n 'Import from the design system, not from {{package}}: the primitives it wraps carry the focus, keyboard and ARIA behaviour the components exist to provide.',\n },\n },\n create(context) {\n const options = (context.options?.[0] ?? {}) as PrimitiveImportOptions\n const prefixes = options.packages ?? DEFAULT_PRIMITIVE_PACKAGES\n const offender = (source: unknown): string | null => {\n const name = String(source ?? '')\n return prefixes.find((prefix) => name === prefix || name.startsWith(`${prefix}/`)) ?? null\n }\n const report = (node: unknown, source: unknown) => {\n const pkg = offender(source)!\n context.report({\n node,\n messageId: 'primitiveImport',\n data: { package: pkg },\n ...(options.message ? { message: options.message } : {}),\n })\n }\n return {\n ImportDeclaration(node: any) {\n if (offender(node.source?.value)) report(node, node.source.value)\n },\n ImportExpression(node: any) {\n if (typeof node.source?.value === 'string' && offender(node.source.value))\n report(node, node.source.value)\n },\n }\n },\n}\n\nconst plugin = {\n meta: { name: 'adea' },\n rules: {\n 'no-raw-interactive-elements': noRawInteractiveElements,\n 'no-primitive-library-imports': noPrimitiveLibraryImports,\n },\n}\n\nexport default plugin\n"],"mappings":";;AAsBA,IAAM,qBACJ,OAAO,OAAO;CACZ,QAAQ;EAAE,WAAW;EAAU,MAAM;CAAmC;CACxE,OAAO;EAAE,WAAW;EAAS,MAAM;CAAkC;CACrE,UAAU;EAAE,WAAW;EAAY,MAAM;CAAqC;CAC9E,QAAQ;EAAE,WAAW;EAAU,MAAM;CAAmC;CACxE,QAAQ;EAAE,WAAW;EAAU,MAAM;CAAmC;CACxE,OAAO;EAAE,WAAW;EAAS,MAAM;CAAkC;AACvE,CAAC;AA6BH,IAAM,2BAAuC;CAC3C,MAAM;EACJ,MAAM;EACN,MAAM,EACJ,aACE,wJACJ;EACA,QAAQ,CACN;GACE,MAAM;GACN,YAAY;IACV,OAAO;KAAE,MAAM;KAAS,OAAO,EAAE,MAAM,SAAS;IAAE;IAClD,SAAS,EAAE,MAAM,SAAS;GAC5B;GACA,sBAAsB;EACxB,CACF;EACA,UAAU,EACR,YACE,4MACJ;CACF;CACA,OAAO,SAAS;EACd,MAAM,UAAW,QAAQ,UAAU,MAAM,CAAC;EAC1C,MAAM,UAAU,IAAI,IAAI,QAAQ,SAAS,CAAC,CAAC;EAC3C,MAAM,QAAQ,MAAe,YAAoB;GAC/C,MAAM,SAAS,mBAAmB;GAClC,QAAQ,OAAO;IACb;IACA,WAAW;IACX,MAAM;KAAE;KAAS,WAAW,OAAO;KAAW,MAAM,OAAO;IAAK;IAChE,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;GACxD,CAAC;EACH;EACA,OAAO,EACL,kBAAkB,MAAW;GAC3B,IAAI,KAAK,MAAM,SAAS,iBAAiB;GACzC,MAAM,UAAU,KAAK,KAAK;GAC1B,IAAI,EAAE,WAAW,uBAAuB,QAAQ,IAAI,OAAO,GAAG;GAC9D,KAAK,MAAM,OAAO;EACpB,EACF;CACF;AACF;AASA,IAAM,6BAA6B,OAAO,OAAO;CAC/C;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAoDD,IAAM,SAAS;CACb,MAAM,EAAE,MAAM,OAAO;CACrB,OAAO;EACL,+BAA+B;EAC/B,gCAAgC;GArDlC,MAAM;IACJ,MAAM;IACN,MAAM,EACJ,aACE,6KACJ;IACA,QAAQ,CACN;KACE,MAAM;KACN,YAAY;MACV,UAAU;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;MAAE;MACrD,SAAS,EAAE,MAAM,SAAS;KAC5B;KACA,sBAAsB;IACxB,CACF;IACA,UAAU,EACR,iBACE,6JACJ;GACF;GACA,OAAO,SAAS;IACd,MAAM,UAAW,QAAQ,UAAU,MAAM,CAAC;IAC1C,MAAM,WAAW,QAAQ,YAAY;IACrC,MAAM,YAAY,WAAmC;KACnD,MAAM,OAAO,OAAO,UAAU,EAAE;KAChC,OAAO,SAAS,MAAM,WAAW,SAAS,UAAU,KAAK,WAAW,GAAG,OAAO,EAAE,CAAC,KAAK;IACxF;IACA,MAAM,UAAU,MAAe,WAAoB;KACjD,MAAM,MAAM,SAAS,MAAM;KAC3B,QAAQ,OAAO;MACb;MACA,WAAW;MACX,MAAM,EAAE,SAAS,IAAI;MACrB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;KACxD,CAAC;IACH;IACA,OAAO;KACL,kBAAkB,MAAW;MAC3B,IAAI,SAAS,KAAK,QAAQ,KAAK,GAAG,OAAO,MAAM,KAAK,OAAO,KAAK;KAClE;KACA,iBAAiB,MAAW;MAC1B,IAAI,OAAO,KAAK,QAAQ,UAAU,YAAY,SAAS,KAAK,OAAO,KAAK,GACtE,OAAO,MAAM,KAAK,OAAO,KAAK;KAClC;IACF;GACF;EAOkC;CAClC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.77.0",
3
+ "version": "0.78.0",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
@@ -59,6 +59,10 @@
59
59
  "development": "./src/lib/*.ts",
60
60
  "import": "./dist/lib/*.js"
61
61
  },
62
+ "./lint": {
63
+ "types": "./dist/lint/index.d.ts",
64
+ "default": "./dist/lint.js"
65
+ },
62
66
  "./globals.css": "./src/styles/globals.css",
63
67
  "./theme.css": "./src/styles/theme.css",
64
68
  "./base.css": "./src/styles/base.css",
@@ -0,0 +1,179 @@
1
+ /*
2
+ * The design system's own oxlint plugin.
3
+ *
4
+ * The styling rules live in `@shadcn/lint`; what that plugin cannot know is which
5
+ * *elements* the design system owns. This is the other half of the contract, for
6
+ * the applications that consume the library: an interactive element this package
7
+ * provides is not re-implemented at the application layer, and the primitive
8
+ * libraries this package is built from are not imported around it.
9
+ *
10
+ * Loaded as an oxlint jsPlugin:
11
+ *
12
+ * // .oxlintrc.json
13
+ * { "jsPlugins": ["@adea-ai/ui/lint"], "rules": { "adea/no-raw-interactive-elements": "error" } }
14
+ *
15
+ * Rules are errors by intent. A violation means an application composed its own
16
+ * control out of raw markup — unreachable focus behaviour, an absent keyboard
17
+ * story, a second implementation of a decision this package exists to make once.
18
+ */
19
+
20
+ type Json = string | number | boolean | null | Json[] | { [key: string]: Json }
21
+
22
+ /** The raw elements this package replaces, and the primitive that replaces them. */
23
+ const ELEMENT_PRIMITIVES: Readonly<Record<string, { primitive: string; path: string }>> =
24
+ Object.freeze({
25
+ button: { primitive: 'Button', path: '@adea-ai/ui/components/ui/button' },
26
+ input: { primitive: 'Input', path: '@adea-ai/ui/components/ui/input' },
27
+ textarea: { primitive: 'Textarea', path: '@adea-ai/ui/components/ui/textarea' },
28
+ select: { primitive: 'Select', path: '@adea-ai/ui/components/ui/select' },
29
+ option: { primitive: 'Select', path: '@adea-ai/ui/components/ui/select' },
30
+ label: { primitive: 'Label', path: '@adea-ai/ui/components/ui/label' },
31
+ })
32
+
33
+ type RuleModule = {
34
+ meta: {
35
+ type: 'problem'
36
+ docs: { description: string }
37
+ schema: Json[]
38
+ messages: Record<string, string>
39
+ }
40
+ create: (context: LintContext) => Record<string, (node: any) => void>
41
+ }
42
+
43
+ interface LintContext {
44
+ options?: unknown[]
45
+ report: (descriptor: {
46
+ node: unknown
47
+ messageId?: string
48
+ message?: string
49
+ data?: Record<string, Json>
50
+ }) => void
51
+ }
52
+
53
+ interface RawElementOptions {
54
+ /** Element names this rule should not report (rare; prefer fixing the file). */
55
+ allow?: string[]
56
+ /** Replaces the default report message. */
57
+ message?: string
58
+ }
59
+
60
+ const noRawInteractiveElements: RuleModule = {
61
+ meta: {
62
+ type: 'problem',
63
+ docs: {
64
+ description:
65
+ 'Interactive elements this package provides (button, input, textarea, select, option, label) are composed from the package, not written as raw markup.',
66
+ },
67
+ schema: [
68
+ {
69
+ type: 'object',
70
+ properties: {
71
+ allow: { type: 'array', items: { type: 'string' } },
72
+ message: { type: 'string' },
73
+ },
74
+ additionalProperties: false,
75
+ },
76
+ ],
77
+ messages: {
78
+ rawElement:
79
+ '{{element}} is provided by the design system: use {{primitive}} from {{path}}. A raw element has no keyboard story, no focus behaviour and no token styling — that is the work the primitive already did.',
80
+ },
81
+ },
82
+ create(context) {
83
+ const options = (context.options?.[0] ?? {}) as RawElementOptions
84
+ const allowed = new Set(options.allow ?? [])
85
+ const emit = (node: unknown, element: string) => {
86
+ const target = ELEMENT_PRIMITIVES[element]!
87
+ context.report({
88
+ node,
89
+ messageId: 'rawElement',
90
+ data: { element, primitive: target.primitive, path: target.path },
91
+ ...(options.message ? { message: options.message } : {}),
92
+ })
93
+ }
94
+ return {
95
+ JSXOpeningElement(node: any) {
96
+ if (node.name?.type !== 'JSXIdentifier') return
97
+ const element = node.name.name
98
+ if (!(element in ELEMENT_PRIMITIVES) || allowed.has(element)) return
99
+ emit(node, element)
100
+ },
101
+ }
102
+ },
103
+ }
104
+
105
+ interface PrimitiveImportOptions {
106
+ /** Package prefixes this rule reports. Defaults to the primitive libraries the ui package wraps. */
107
+ packages?: string[]
108
+ /** Replaces the default report message. */
109
+ message?: string
110
+ }
111
+
112
+ const DEFAULT_PRIMITIVE_PACKAGES = Object.freeze([
113
+ '@kobalte/core',
114
+ '@ark-ui',
115
+ '@zag-js',
116
+ '@radix-ui',
117
+ 'radix-ui',
118
+ '@base-ui-components',
119
+ ])
120
+
121
+ const noPrimitiveLibraryImports: RuleModule = {
122
+ meta: {
123
+ type: 'problem',
124
+ docs: {
125
+ description:
126
+ 'The primitive libraries the design system is built on (Kobalte and friends) are its internal affair — compose the exported components instead of importing the primitives.',
127
+ },
128
+ schema: [
129
+ {
130
+ type: 'object',
131
+ properties: {
132
+ packages: { type: 'array', items: { type: 'string' } },
133
+ message: { type: 'string' },
134
+ },
135
+ additionalProperties: false,
136
+ },
137
+ ],
138
+ messages: {
139
+ primitiveImport:
140
+ 'Import from the design system, not from {{package}}: the primitives it wraps carry the focus, keyboard and ARIA behaviour the components exist to provide.',
141
+ },
142
+ },
143
+ create(context) {
144
+ const options = (context.options?.[0] ?? {}) as PrimitiveImportOptions
145
+ const prefixes = options.packages ?? DEFAULT_PRIMITIVE_PACKAGES
146
+ const offender = (source: unknown): string | null => {
147
+ const name = String(source ?? '')
148
+ return prefixes.find((prefix) => name === prefix || name.startsWith(`${prefix}/`)) ?? null
149
+ }
150
+ const report = (node: unknown, source: unknown) => {
151
+ const pkg = offender(source)!
152
+ context.report({
153
+ node,
154
+ messageId: 'primitiveImport',
155
+ data: { package: pkg },
156
+ ...(options.message ? { message: options.message } : {}),
157
+ })
158
+ }
159
+ return {
160
+ ImportDeclaration(node: any) {
161
+ if (offender(node.source?.value)) report(node, node.source.value)
162
+ },
163
+ ImportExpression(node: any) {
164
+ if (typeof node.source?.value === 'string' && offender(node.source.value))
165
+ report(node, node.source.value)
166
+ },
167
+ }
168
+ },
169
+ }
170
+
171
+ const plugin = {
172
+ meta: { name: 'adea' },
173
+ rules: {
174
+ 'no-raw-interactive-elements': noRawInteractiveElements,
175
+ 'no-primitive-library-imports': noPrimitiveLibraryImports,
176
+ },
177
+ }
178
+
179
+ export default plugin