@camunda/design-system 0.62.0 → 0.64.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.
Files changed (91) hide show
  1. package/dist/src/components/ui/alert-dialog.d.ts +1 -1
  2. package/dist/src/components/ui/alert-dialog.d.ts.map +1 -1
  3. package/dist/src/components/ui/alert-dialog.js +3 -1
  4. package/dist/src/components/ui/alert-dialog.js.map +1 -1
  5. package/dist/src/components/ui/app-sidebar.d.ts +7 -15
  6. package/dist/src/components/ui/app-sidebar.d.ts.map +1 -1
  7. package/dist/src/components/ui/app-sidebar.js +192 -55
  8. package/dist/src/components/ui/app-sidebar.js.map +1 -1
  9. package/dist/src/components/ui/collapsible.d.ts +1 -1
  10. package/dist/src/components/ui/collapsible.d.ts.map +1 -1
  11. package/dist/src/components/ui/collapsible.js +3 -1
  12. package/dist/src/components/ui/collapsible.js.map +1 -1
  13. package/dist/src/components/ui/data-table.d.ts +17 -2
  14. package/dist/src/components/ui/data-table.d.ts.map +1 -1
  15. package/dist/src/components/ui/data-table.js +16 -7
  16. package/dist/src/components/ui/data-table.js.map +1 -1
  17. package/dist/src/components/ui/dialog.d.ts +1 -1
  18. package/dist/src/components/ui/dialog.d.ts.map +1 -1
  19. package/dist/src/components/ui/dialog.js +3 -1
  20. package/dist/src/components/ui/dialog.js.map +1 -1
  21. package/dist/src/components/ui/dropdown.d.ts +3 -3
  22. package/dist/src/components/ui/dropdown.d.ts.map +1 -1
  23. package/dist/src/components/ui/dropdown.js +7 -2
  24. package/dist/src/components/ui/dropdown.js.map +1 -1
  25. package/dist/src/components/ui/input.d.ts.map +1 -1
  26. package/dist/src/components/ui/input.js +7 -4
  27. package/dist/src/components/ui/input.js.map +1 -1
  28. package/dist/src/components/ui/popover.d.ts +1 -1
  29. package/dist/src/components/ui/popover.d.ts.map +1 -1
  30. package/dist/src/components/ui/popover.js +8 -1
  31. package/dist/src/components/ui/popover.js.map +1 -1
  32. package/dist/src/components/ui/select.d.ts +1 -1
  33. package/dist/src/components/ui/select.d.ts.map +1 -1
  34. package/dist/src/components/ui/select.js +16 -9
  35. package/dist/src/components/ui/select.js.map +1 -1
  36. package/dist/src/components/ui/sheet.d.ts +1 -1
  37. package/dist/src/components/ui/sheet.d.ts.map +1 -1
  38. package/dist/src/components/ui/sheet.js +3 -1
  39. package/dist/src/components/ui/sheet.js.map +1 -1
  40. package/dist/src/components/ui/sidebar-provider.d.ts +7 -1
  41. package/dist/src/components/ui/sidebar-provider.d.ts.map +1 -1
  42. package/dist/src/components/ui/sidebar-provider.js +10 -6
  43. package/dist/src/components/ui/sidebar-provider.js.map +1 -1
  44. package/dist/src/components/ui/tabs.d.ts +1 -1
  45. package/dist/src/components/ui/tabs.d.ts.map +1 -1
  46. package/dist/src/components/ui/tabs.js +2 -1
  47. package/dist/src/components/ui/tabs.js.map +1 -1
  48. package/dist/src/components/ui/textarea.d.ts.map +1 -1
  49. package/dist/src/components/ui/textarea.js +8 -5
  50. package/dist/src/components/ui/textarea.js.map +1 -1
  51. package/dist/src/components/ui/tooltip.d.ts +1 -1
  52. package/dist/src/components/ui/tooltip.d.ts.map +1 -1
  53. package/dist/src/components/ui/tooltip.js +5 -1
  54. package/dist/src/components/ui/tooltip.js.map +1 -1
  55. package/dist/src/icons/index.d.ts +1 -1
  56. package/dist/src/icons/index.d.ts.map +1 -1
  57. package/dist/src/icons/index.js +1 -1
  58. package/dist/src/icons/index.js.map +1 -1
  59. package/dist/src/icons/registry.d.ts +1 -0
  60. package/dist/src/icons/registry.d.ts.map +1 -1
  61. package/dist/src/icons/registry.js +3 -1
  62. package/dist/src/icons/registry.js.map +1 -1
  63. package/dist/src/icons/registry.json +12 -4
  64. package/dist/src/index.d.ts +1 -1
  65. package/dist/src/index.d.ts.map +1 -1
  66. package/dist/src/index.js +1 -1
  67. package/dist/src/index.js.map +1 -1
  68. package/dist/src/lib/i18n/dictionary.d.ts +0 -1
  69. package/dist/src/lib/i18n/dictionary.d.ts.map +1 -1
  70. package/dist/src/lib/i18n/dictionary.js +0 -1
  71. package/dist/src/lib/i18n/dictionary.js.map +1 -1
  72. package/dist/styles.css +49 -34
  73. package/eslint-plugin/index.d.ts +18 -0
  74. package/eslint-plugin/index.js +102 -0
  75. package/eslint-rules/button-has-type.js +56 -0
  76. package/eslint-rules/class-literal.js +20 -0
  77. package/eslint-rules/ds-imports.js +131 -0
  78. package/eslint-rules/icon-button-needs-label.js +110 -0
  79. package/eslint-rules/index.js +31 -0
  80. package/eslint-rules/navigation.js +295 -0
  81. package/eslint-rules/no-adhoc-typography.js +77 -0
  82. package/eslint-rules/no-deep-import.js +59 -0
  83. package/eslint-rules/no-direct-lucide-import.js +67 -0
  84. package/eslint-rules/no-hardcoded-i18n-prop.js +78 -0
  85. package/eslint-rules/no-hardcoded-user-facing-string.js +82 -0
  86. package/eslint-rules/no-primitive-tailwind-colors.js +36 -0
  87. package/eslint-rules/no-raw-color-in-classname.js +34 -0
  88. package/eslint-rules/prefer-link-props.js +107 -0
  89. package/eslint-rules/require-browsable-link.js +236 -0
  90. package/eslint-rules/require-shared-sidebar-provider.js +165 -0
  91. package/package.json +18 -3
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Flags `<AppHeader>` and `<AppSidebar>` composed in the same file without a
3
+ * shared `<SidebarProvider>` ancestor. Without one, each reads a separate
4
+ * (or missing) sidebar context — `AppHeader`'s `isMobile` check silently
5
+ * reads `false` regardless of viewport, the mobile hamburger never renders,
6
+ * and `AppSidebar` renders its fixed desktop rail on a phone screen instead
7
+ * of the mobile Sheet overlay (issue #470).
8
+ *
9
+ * Either component used alone (no sidebar at all, or a sidebar-only shell)
10
+ * is a legitimate, documented composition and must never warn — this rule
11
+ * only fires when BOTH are present and don't share one provider instance.
12
+ *
13
+ * Same-file heuristic only: it cannot see a provider wrapping either
14
+ * component from a different file (e.g. a router rendering each at a
15
+ * different route level) — that case is covered by AppSidebar's own
16
+ * dev-mode runtime warning instead, not by static analysis.
17
+ *
18
+ * Optional `importSources`: when set, only `AppHeader`/`AppSidebar` imported
19
+ * from those modules count (aliases resolved), so a consumer's own component
20
+ * with the same name never trips it. `SidebarProvider` is still matched by
21
+ * bare name as well — a local re-export of the provider is a valid ancestor.
22
+ * Without the option (DS repo, relative imports) names match bare.
23
+ */
24
+ import { importSourcesSchema, trackDsImports } from "./ds-imports.js";
25
+
26
+ export default {
27
+ meta: {
28
+ type: "problem",
29
+ docs: {
30
+ description:
31
+ "AppHeader and AppSidebar must share one SidebarProvider ancestor when both are used.",
32
+ },
33
+ messages: {
34
+ missingSharedProvider:
35
+ "<{{name}}> is composed with <{{other}}> in this file but they don't share a <SidebarProvider> ancestor — the mobile hamburger/Sheet overlay will silently fail to work. Wrap both in one shared <SidebarProvider>.",
36
+ },
37
+ schema: [importSourcesSchema],
38
+ },
39
+ create(context) {
40
+ const scoped = Boolean(context.options[0]?.importSources);
41
+ const ds = trackDsImports(context);
42
+ const NAMES = ["AppHeader", "AppSidebar"];
43
+ const otherName = (name) =>
44
+ name === "AppHeader" ? "AppSidebar" : "AppHeader";
45
+ const FUNCTION_TYPES = new Set([
46
+ "FunctionDeclaration",
47
+ "FunctionExpression",
48
+ "ArrowFunctionExpression",
49
+ ]);
50
+
51
+ // Grouping key: the nearest enclosing COMPONENT-level function (each
52
+ // component is its own scope — an AppHeader in one component has nothing
53
+ // to do with an AppSidebar in an unrelated one, even in the same file).
54
+ // `null` = module top level, its own scope too.
55
+ // A plain helper function nested inside a component (e.g.
56
+ // `const header = () => <AppHeader />`) is NOT a new scope — it inherits
57
+ // its enclosing component's scope, so JSX it returns still gets grouped
58
+ // with siblings rendered directly in that component.
59
+ // key -> { AppHeader: [{node, providerAncestors}], AppSidebar: [...] }
60
+ const scopes = new Map();
61
+ const providerStack = [];
62
+ const functionStack = [];
63
+
64
+ function elementName(node) {
65
+ const n = node.openingElement.name;
66
+ if (n.type !== "JSXIdentifier") return null;
67
+ return scoped ? ds.importedName(n) : n.name;
68
+ }
69
+
70
+ function isProvider(node) {
71
+ const n = node.openingElement.name;
72
+ return (
73
+ (n.type === "JSXIdentifier" && n.name === "SidebarProvider") ||
74
+ elementName(node) === "SidebarProvider"
75
+ );
76
+ }
77
+
78
+ function currentScopeKey() {
79
+ return functionStack.length
80
+ ? functionStack[functionStack.length - 1]
81
+ : null;
82
+ }
83
+
84
+ function isComponentScope(node) {
85
+ if (
86
+ (node.type === "FunctionDeclaration" ||
87
+ node.type === "FunctionExpression") &&
88
+ node.id &&
89
+ /^[A-Z]/.test(node.id.name)
90
+ ) {
91
+ return true;
92
+ }
93
+ const parent = node.parent;
94
+ return (
95
+ parent?.type === "VariableDeclarator" &&
96
+ parent.id.type === "Identifier" &&
97
+ /^[A-Z]/.test(parent.id.name)
98
+ );
99
+ }
100
+
101
+ function pushFn(node) {
102
+ if (FUNCTION_TYPES.has(node.type) && isComponentScope(node)) {
103
+ functionStack.push(node);
104
+ }
105
+ }
106
+ function popFn(node) {
107
+ if (
108
+ FUNCTION_TYPES.has(node.type) &&
109
+ functionStack[functionStack.length - 1] === node
110
+ ) {
111
+ functionStack.pop();
112
+ }
113
+ }
114
+
115
+ return {
116
+ ImportDeclaration: ds.ImportDeclaration,
117
+ FunctionDeclaration: pushFn,
118
+ FunctionExpression: pushFn,
119
+ ArrowFunctionExpression: pushFn,
120
+ "FunctionDeclaration:exit": popFn,
121
+ "FunctionExpression:exit": popFn,
122
+ "ArrowFunctionExpression:exit": popFn,
123
+
124
+ JSXElement(node) {
125
+ const name = elementName(node);
126
+ if (isProvider(node)) providerStack.push(node);
127
+ if (!NAMES.includes(name)) return;
128
+
129
+ const key = currentScopeKey();
130
+ if (!scopes.has(key))
131
+ scopes.set(key, { AppHeader: [], AppSidebar: [] });
132
+ scopes.get(key)[name].push({
133
+ node,
134
+ providerAncestors: new Set(providerStack),
135
+ });
136
+ },
137
+ "JSXElement:exit"(node) {
138
+ if (isProvider(node)) providerStack.pop();
139
+ },
140
+ "Program:exit"() {
141
+ for (const occurrences of scopes.values()) {
142
+ for (const name of NAMES) {
143
+ const other = otherName(name);
144
+ if (occurrences[other].length === 0) continue; // used alone — fine
145
+
146
+ for (const occ of occurrences[name]) {
147
+ const sharesProvider = occurrences[other].some((otherOcc) =>
148
+ [...occ.providerAncestors].some((p) =>
149
+ otherOcc.providerAncestors.has(p),
150
+ ),
151
+ );
152
+ if (!sharesProvider) {
153
+ context.report({
154
+ node: occ.node,
155
+ messageId: "missingSharedProvider",
156
+ data: { name, other },
157
+ });
158
+ }
159
+ }
160
+ }
161
+ }
162
+ },
163
+ };
164
+ },
165
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/design-system",
3
- "version": "0.62.0",
3
+ "version": "0.64.0",
4
4
  "description": "Camunda's AI-first design system. shadcn + Tailwind components, design tokens aligned to Camunda's identity, and AI tooling for component authoring + migration.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,17 +29,28 @@
29
29
  "types": "./dist/carbon-compat/index.d.ts",
30
30
  "import": "./dist/carbon-compat/index.js"
31
31
  },
32
+ "./eslint-plugin": {
33
+ "types": "./eslint-plugin/index.d.ts",
34
+ "import": "./eslint-plugin/index.js"
35
+ },
32
36
  "./styles.css": "./dist/styles.css"
33
37
  },
34
38
  "typesVersions": {
35
39
  "*": {
36
40
  "carbon-compat": [
37
41
  "./dist/carbon-compat/index.d.ts"
42
+ ],
43
+ "eslint-plugin": [
44
+ "./eslint-plugin/index.d.ts"
38
45
  ]
39
46
  }
40
47
  },
41
48
  "files": [
42
49
  "dist",
50
+ "eslint-plugin",
51
+ "!eslint-plugin/*.test.mjs",
52
+ "eslint-rules",
53
+ "!eslint-rules/*.test.mjs",
43
54
  "README.md",
44
55
  "LICENSE",
45
56
  "NOTICE"
@@ -73,7 +84,7 @@
73
84
  "audit:conventions": "node scripts/audit-conventions.mjs",
74
85
  "mapping:build": "bash skills/migrate/scripts/build-mapping.sh",
75
86
  "mapping:check": "bash skills/migrate/scripts/build-mapping.sh --check",
76
- "test:rules": "node eslint-rules/no-adhoc-typography.test.mjs && node eslint-rules/no-primitive-tailwind-colors.test.mjs && node eslint-rules/no-raw-color-in-classname.test.mjs && node eslint-rules/require-shared-sidebar-provider.test.mjs && node eslint-rules/no-direct-lucide-import.test.mjs && node eslint-rules/no-hardcoded-user-facing-string.test.mjs && node --test src/icons/registry.integrity.test.mjs src/lib/i18n/dictionary.test.mjs src/lib/i18n/dictionary-usage.test.mjs src/lib/i18n/context.test.mjs",
87
+ "test:rules": "node eslint-rules/no-adhoc-typography.test.mjs && node eslint-rules/no-primitive-tailwind-colors.test.mjs && node eslint-rules/no-raw-color-in-classname.test.mjs && node eslint-rules/require-shared-sidebar-provider.test.mjs && node eslint-rules/no-hardcoded-user-facing-string.test.mjs && node eslint-rules/no-direct-lucide-import.test.mjs && node eslint-rules/no-deep-import.test.mjs && node eslint-rules/button-has-type.test.mjs && node eslint-rules/icon-button-needs-label.test.mjs && node eslint-rules/prefer-link-props.test.mjs && node eslint-rules/require-browsable-link.test.mjs && node eslint-rules/no-hardcoded-i18n-prop.test.mjs && node --test eslint-plugin/index.test.mjs src/icons/registry.integrity.test.mjs src/lib/trigger-ref.integrity.test.mjs src/lib/i18n/dictionary.test.mjs src/lib/i18n/dictionary-usage.test.mjs src/lib/i18n/context.test.mjs",
77
88
  "test:hooks": "python3 plugins/camunda-design-system/scripts/route-request.test.py",
78
89
  "prepare": "husky",
79
90
  "release": "changeset publish",
@@ -93,11 +104,15 @@
93
104
  "peerDependencies": {
94
105
  "@carbon/react": "^1.107.0",
95
106
  "react": ">=19.0.0 <20",
96
- "react-dom": ">=19.0.0 <20"
107
+ "react-dom": ">=19.0.0 <20",
108
+ "eslint": ">=9.0.0"
97
109
  },
98
110
  "peerDependenciesMeta": {
99
111
  "@carbon/react": {
100
112
  "optional": true
113
+ },
114
+ "eslint": {
115
+ "optional": true
101
116
  }
102
117
  },
103
118
  "dependencies": {