@edgeandnode/eds-react 1.1.0 → 1.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.
Files changed (118) hide show
  1. package/README.md +27 -3
  2. package/dist/components/Address.d.ts +3 -3
  3. package/dist/components/Address.d.ts.map +1 -1
  4. package/dist/components/Address.js +1 -1
  5. package/dist/components/Address.js.map +1 -1
  6. package/dist/components/Avatar.d.ts +3 -3
  7. package/dist/components/Avatar.d.ts.map +1 -1
  8. package/dist/components/Avatar.js +13 -1
  9. package/dist/components/Avatar.js.map +1 -1
  10. package/dist/components/Breadcrumbs.parts.d.ts +3 -3
  11. package/dist/components/Breadcrumbs.parts.d.ts.map +1 -1
  12. package/dist/components/Breadcrumbs.parts.js +1 -1
  13. package/dist/components/Breadcrumbs.parts.js.map +1 -1
  14. package/dist/components/Button.js +1 -1
  15. package/dist/components/Button.js.map +1 -1
  16. package/dist/components/Card.js +1 -1
  17. package/dist/components/Card.js.map +1 -1
  18. package/dist/components/Chip.parts.d.ts.map +1 -1
  19. package/dist/components/Chip.parts.js +1 -1
  20. package/dist/components/Chip.parts.js.map +1 -1
  21. package/dist/components/Cluster.d.ts +3 -3
  22. package/dist/components/Cluster.d.ts.map +1 -1
  23. package/dist/components/Cluster.js.map +1 -1
  24. package/dist/components/Icon.d.ts.map +1 -1
  25. package/dist/components/Icon.js +0 -2
  26. package/dist/components/Icon.js.map +1 -1
  27. package/dist/components/Link.d.ts.map +1 -1
  28. package/dist/components/Link.js +2 -0
  29. package/dist/components/Link.js.map +1 -1
  30. package/dist/components/Menu.parts.js +1 -1
  31. package/dist/components/Menu.parts.js.map +1 -1
  32. package/dist/components/Search.d.ts.map +1 -1
  33. package/dist/components/Search.js +1 -1
  34. package/dist/components/Search.js.map +1 -1
  35. package/dist/components/SegmentedControl.parts.d.ts.map +1 -1
  36. package/dist/components/SegmentedControl.parts.js +1 -1
  37. package/dist/components/SegmentedControl.parts.js.map +1 -1
  38. package/dist/components/TabSet.parts.js +1 -1
  39. package/dist/components/TabSet.parts.js.map +1 -1
  40. package/dist/components/Tooltip.parts.d.ts.map +1 -1
  41. package/dist/components/Tooltip.parts.js.map +1 -1
  42. package/dist/components/base/Checkable.parts.js +1 -1
  43. package/dist/components/base/Checkable.parts.js.map +1 -1
  44. package/dist/components/base/Field.parts.js +1 -1
  45. package/dist/components/base/Field.parts.js.map +1 -1
  46. package/dist/components/base/Portal.js +3 -3
  47. package/dist/components/base/Portal.js.map +1 -1
  48. package/dist/components/base/Transition.js +1 -1
  49. package/dist/components/base/Transition.js.map +1 -1
  50. package/dist/hooks/useCSSPropsPolyfill.d.ts.map +1 -1
  51. package/dist/hooks/useCSSPropsPolyfill.js +7 -19
  52. package/dist/hooks/useCSSPropsPolyfill.js.map +1 -1
  53. package/dist/hooks/useCSSState.d.ts +4 -0
  54. package/dist/hooks/useCSSState.d.ts.map +1 -1
  55. package/dist/hooks/useCSSState.js +24 -6
  56. package/dist/hooks/useCSSState.js.map +1 -1
  57. package/dist/hooks/useStyleObserver.d.ts.map +1 -1
  58. package/dist/hooks/useStyleObserver.js +9 -5
  59. package/dist/hooks/useStyleObserver.js.map +1 -1
  60. package/dist/postcss-plugin.d.ts +2 -0
  61. package/dist/postcss-plugin.d.ts.map +1 -0
  62. package/dist/postcss-plugin.js +2 -0
  63. package/dist/postcss-plugin.js.map +1 -0
  64. package/dist/utils/internal/BatchedElementStyleObserver.d.ts +13 -0
  65. package/dist/utils/internal/BatchedElementStyleObserver.d.ts.map +1 -0
  66. package/dist/utils/internal/BatchedElementStyleObserver.js +28 -0
  67. package/dist/utils/internal/BatchedElementStyleObserver.js.map +1 -0
  68. package/dist/utils/internal/getStyleQueriesSupported.d.ts +2 -0
  69. package/dist/utils/internal/getStyleQueriesSupported.d.ts.map +1 -0
  70. package/dist/utils/internal/getStyleQueriesSupported.js +12 -0
  71. package/dist/utils/internal/getStyleQueriesSupported.js.map +1 -0
  72. package/dist/utils/internal/index.d.ts +2 -0
  73. package/dist/utils/internal/index.d.ts.map +1 -1
  74. package/dist/utils/internal/index.js +2 -0
  75. package/dist/utils/internal/index.js.map +1 -1
  76. package/dist/utils/internal/styleScheduler.d.ts +8 -3
  77. package/dist/utils/internal/styleScheduler.d.ts.map +1 -1
  78. package/dist/utils/internal/styleScheduler.js +46 -16
  79. package/dist/utils/internal/styleScheduler.js.map +1 -1
  80. package/dist/utils/styleObserver.d.ts +2 -0
  81. package/dist/utils/styleObserver.d.ts.map +1 -1
  82. package/dist/utils/styleObserver.js +40 -33
  83. package/dist/utils/styleObserver.js.map +1 -1
  84. package/dist/vite-plugin.d.ts +2 -0
  85. package/dist/vite-plugin.d.ts.map +1 -0
  86. package/dist/vite-plugin.js +2 -0
  87. package/dist/vite-plugin.js.map +1 -0
  88. package/package.json +13 -11
  89. package/scripts/update-skill.cjs +42 -0
  90. package/skill/SKILL.md +18 -14
  91. package/src/components/Address.tsx +12 -10
  92. package/src/components/Avatar.tsx +61 -49
  93. package/src/components/Breadcrumbs.parts.tsx +11 -9
  94. package/src/components/Button.tsx +1 -1
  95. package/src/components/Card.tsx +1 -1
  96. package/src/components/Chip.parts.tsx +9 -6
  97. package/src/components/Cluster.tsx +3 -5
  98. package/src/components/Icon.tsx +0 -2
  99. package/src/components/Link.tsx +2 -0
  100. package/src/components/Menu.parts.tsx +1 -1
  101. package/src/components/Search.tsx +9 -6
  102. package/src/components/SegmentedControl.parts.tsx +8 -5
  103. package/src/components/TabSet.parts.tsx +1 -1
  104. package/src/components/Tooltip.parts.tsx +4 -1
  105. package/src/components/base/Checkable.parts.tsx +1 -1
  106. package/src/components/base/Field.parts.tsx +1 -1
  107. package/src/components/base/Portal.tsx +3 -3
  108. package/src/components/base/Transition.tsx +1 -1
  109. package/src/hooks/useCSSPropsPolyfill.ts +7 -20
  110. package/src/hooks/useCSSState.ts +29 -8
  111. package/src/hooks/useStyleObserver.ts +18 -14
  112. package/src/postcss-plugin.ts +1 -0
  113. package/src/utils/internal/BatchedElementStyleObserver.ts +31 -0
  114. package/src/utils/internal/getStyleQueriesSupported.ts +11 -0
  115. package/src/utils/internal/index.ts +2 -0
  116. package/src/utils/internal/styleScheduler.ts +43 -15
  117. package/src/utils/styleObserver.ts +38 -40
  118. package/src/vite-plugin.ts +1 -0
@@ -0,0 +1,28 @@
1
+ import { ElementStyleObserver } from 'style-observer';
2
+ /**
3
+ * `style-observer` reads computed styles between its transition writes on each new target. Buffer
4
+ * those first writes so every target can read its original styles before any transitions change.
5
+ * Subsequent updates retain the library's transition and browser compatibility handling.
6
+ */
7
+ export class BatchedElementStyleObserver extends ElementStyleObserver {
8
+ pendingStyles = new Map();
9
+ setProperty(property, value, priority) {
10
+ if (this.pendingStyles) {
11
+ this.pendingStyles.set(property, { value, priority });
12
+ }
13
+ else {
14
+ super.setProperty(property, value, priority);
15
+ }
16
+ }
17
+ getProperty(property) {
18
+ return this.pendingStyles?.get(property)?.value ?? super.getProperty(property);
19
+ }
20
+ flush() {
21
+ const pendingStyles = this.pendingStyles;
22
+ this.pendingStyles = undefined;
23
+ for (const [property, { value, priority }] of pendingStyles ?? []) {
24
+ super.setProperty(property, value, priority);
25
+ }
26
+ }
27
+ }
28
+ //# sourceMappingURL=BatchedElementStyleObserver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BatchedElementStyleObserver.js","sourceRoot":"","sources":["../../../src/utils/internal/BatchedElementStyleObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;;GAIG;AACH,MAAM,OAAO,2BAA4B,SAAQ,oBAAoB;IAC3D,aAAa,GACnB,IAAI,GAAG,EAAE,CAAA;IAEF,WAAW,CAAC,QAAgB,EAAE,KAAa,EAAE,QAAiB;QACrE,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACvD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAEQ,WAAW,CAAC,QAAgB;QACnC,OAAO,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IAChF,CAAC;IAED,KAAK;QACH,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;QACxC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;QAC9B,KAAK,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,IAAI,aAAa,IAAI,EAAE,EAAE,CAAC;YAClE,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export declare function getStyleQueriesSupported(): boolean;
2
+ //# sourceMappingURL=getStyleQueriesSupported.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getStyleQueriesSupported.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/getStyleQueriesSupported.ts"],"names":[],"mappings":"AAEA,wBAAgB,wBAAwB,IAAI,OAAO,CAQlD"}
@@ -0,0 +1,12 @@
1
+ let styleQueriesSupported = null;
2
+ export function getStyleQueriesSupported() {
3
+ if (typeof window === 'undefined' || typeof document === 'undefined')
4
+ return false;
5
+ if (styleQueriesSupported === null) {
6
+ styleQueriesSupported =
7
+ window.getComputedStyle(document.body).getPropertyValue('--eds-style-queries-test') ===
8
+ 'success';
9
+ }
10
+ return styleQueriesSupported;
11
+ }
12
+ //# sourceMappingURL=getStyleQueriesSupported.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getStyleQueriesSupported.js","sourceRoot":"","sources":["../../../src/utils/internal/getStyleQueriesSupported.ts"],"names":[],"mappings":"AAAA,IAAI,qBAAqB,GAAmB,IAAI,CAAA;AAEhD,MAAM,UAAU,wBAAwB;IACtC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAClF,IAAI,qBAAqB,KAAK,IAAI,EAAE,CAAC;QACnC,qBAAqB;YACnB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,0BAA0B,CAAC;gBACnF,SAAS,CAAA;IACb,CAAC;IACD,OAAO,qBAAqB,CAAA;AAC9B,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export { getTooltipProps } from './getTooltipProps.ts';
2
2
  export { isLazy, resolveLazy } from './resolveLazy.ts';
3
3
  export { styleScheduler } from './styleScheduler.ts';
4
+ export { BatchedElementStyleObserver } from './BatchedElementStyleObserver.ts';
5
+ export { getStyleQueriesSupported } from './getStyleQueriesSupported.ts';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA"}
@@ -1,4 +1,6 @@
1
1
  export { getTooltipProps } from './getTooltipProps.js';
2
2
  export { isLazy, resolveLazy } from './resolveLazy.js';
3
3
  export { styleScheduler } from './styleScheduler.js';
4
+ export { BatchedElementStyleObserver } from './BatchedElementStyleObserver.js';
5
+ export { getStyleQueriesSupported } from './getStyleQueriesSupported.js';
4
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA"}
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Batched style scheduler that collects style operations within a single frame and executes them
3
- * together using `requestAnimationFrame`. This reduces layout thrashing by batching all operations
4
- * into a single reflow.
3
+ * together using `requestAnimationFrame`. Reads run before writes to avoid layout thrashing.
5
4
  *
6
5
  * @example
7
6
  * ````ts
@@ -22,14 +21,20 @@
22
21
  * ````
23
22
  */
24
23
  declare class StyleScheduler {
25
- private rafId;
24
+ private animationFrameId;
26
25
  private pending;
26
+ private pendingWrites;
27
27
  /**
28
28
  * Schedule an operation to be executed in the next animation frame. All operations scheduled
29
29
  * within the same frame will be batched together and executed synchronously in a single batch.
30
30
  * Returns a function that cancels the scheduled callback if it hasn't run yet.
31
31
  */
32
32
  schedule(callback: () => void): () => void;
33
+ /** Schedule a write after all reads in the frame, including writes queued during those reads. */
34
+ scheduleWrite(callback: () => void): () => void;
35
+ private enqueue;
36
+ private runBatch;
37
+ private requestFrame;
33
38
  /**
34
39
  * Get computed style for an element in a batched manner. Returns a promise that resolves with the
35
40
  * computed style once all batched operations are executed.
@@ -1 +1 @@
1
- {"version":3,"file":"styleScheduler.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/styleScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAM,cAAc;IAClB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,OAAO,CAAqB;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAiBzC;IAED;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAM/D;CACF;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAA"}
1
+ {"version":3,"file":"styleScheduler.d.ts","sourceRoot":"","sources":["../../../src/utils/internal/styleScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,cAAM,cAAc;IAClB,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,aAAa,CAAwB;IAE7C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAEzC;IAED,iGAAiG;IACjG,aAAa,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAE9C;IAED,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,YAAY;IAiBpB;;;OAGG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAM/D;CACF;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAA"}
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Batched style scheduler that collects style operations within a single frame and executes them
3
- * together using `requestAnimationFrame`. This reduces layout thrashing by batching all operations
4
- * into a single reflow.
3
+ * together using `requestAnimationFrame`. Reads run before writes to avoid layout thrashing.
5
4
  *
6
5
  * @example
7
6
  * ````ts
@@ -22,29 +21,60 @@
22
21
  * ````
23
22
  */
24
23
  class StyleScheduler {
25
- rafId = null;
26
- pending = [];
24
+ animationFrameId = null;
25
+ pending = new Set();
26
+ pendingWrites = new Set();
27
27
  /**
28
28
  * Schedule an operation to be executed in the next animation frame. All operations scheduled
29
29
  * within the same frame will be batched together and executed synchronously in a single batch.
30
30
  * Returns a function that cancels the scheduled callback if it hasn't run yet.
31
31
  */
32
32
  schedule(callback) {
33
- this.pending.push(callback);
34
- if (this.rafId === null) {
35
- this.rafId = requestAnimationFrame(() => {
36
- const callbacks = this.pending;
37
- this.pending = [];
38
- this.rafId = null;
39
- callbacks.forEach((cb) => cb());
40
- });
41
- }
33
+ return this.enqueue(callback, this.pending);
34
+ }
35
+ /** Schedule a write after all reads in the frame, including writes queued during those reads. */
36
+ scheduleWrite(callback) {
37
+ return this.enqueue(callback, this.pendingWrites);
38
+ }
39
+ enqueue(callback, queue) {
40
+ const operation = () => callback();
41
+ queue.add(operation);
42
+ this.requestFrame();
42
43
  return () => {
43
- const index = this.pending.indexOf(callback);
44
- if (index !== -1)
45
- this.pending.splice(index, 1);
44
+ queue.delete(operation);
46
45
  };
47
46
  }
47
+ runBatch(queue) {
48
+ try {
49
+ for (const callback of queue) {
50
+ queue.delete(callback);
51
+ callback();
52
+ }
53
+ }
54
+ finally {
55
+ // Cancellation closures can outlive the batch, including when a callback throws.
56
+ queue.clear();
57
+ }
58
+ }
59
+ requestFrame() {
60
+ if (this.animationFrameId !== null)
61
+ return;
62
+ this.animationFrameId = requestAnimationFrame(() => {
63
+ const callbacks = this.pending;
64
+ this.pending = new Set();
65
+ try {
66
+ this.runBatch(callbacks);
67
+ const writes = this.pendingWrites;
68
+ this.pendingWrites = new Set();
69
+ this.runBatch(writes);
70
+ }
71
+ finally {
72
+ this.animationFrameId = null;
73
+ if (this.pending.size > 0 || this.pendingWrites.size > 0)
74
+ this.requestFrame();
75
+ }
76
+ });
77
+ }
48
78
  /**
49
79
  * Get computed style for an element in a batched manner. Returns a promise that resolves with the
50
80
  * computed style once all batched operations are executed.
@@ -1 +1 @@
1
- {"version":3,"file":"styleScheduler.js","sourceRoot":"","sources":["../../../src/utils/internal/styleScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,cAAc;IACV,KAAK,GAAkB,IAAI,CAAA;IAC3B,OAAO,GAAmB,EAAE,CAAA;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,QAAoB;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE3B,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,GAAG,EAAE;gBACtC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAA;gBAC9B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;gBACjB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;gBAEjB,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;YACjC,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,GAAG,EAAE;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YAC5C,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACjD,CAAC,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,OAAgB;QAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACjB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;YAC3C,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"styleScheduler.js","sourceRoot":"","sources":["../../../src/utils/internal/styleScheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,cAAc;IACV,gBAAgB,GAAkB,IAAI,CAAA;IACtC,OAAO,GAAG,IAAI,GAAG,EAAc,CAAA;IAC/B,aAAa,GAAG,IAAI,GAAG,EAAc,CAAA;IAE7C;;;;OAIG;IACH,QAAQ,CAAC,QAAoB;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7C,CAAC;IAED,iGAAiG;IACjG,aAAa,CAAC,QAAoB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;IACnD,CAAC;IAEO,OAAO,CAAC,QAAoB,EAAE,KAAsB;QAC1D,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;QAClC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACpB,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACzB,CAAC,CAAA;IACH,CAAC;IAEO,QAAQ,CAAC,KAAsB;QACrC,IAAI,CAAC;YACH,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;gBAC7B,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACtB,QAAQ,EAAE,CAAA;YACZ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,iFAAiF;YACjF,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI;YAAE,OAAM;QAC1C,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,GAAG,EAAE;YACjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAA;YAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAA;YACxB,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;gBACxB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAA;gBACjC,IAAI,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAA;gBAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAA;gBAC5B,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC;oBAAE,IAAI,CAAC,YAAY,EAAE,CAAA;YAC/E,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,OAAgB;QAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACjB,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;YAC3C,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kDAAkD;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAA"}
@@ -21,6 +21,8 @@ declare class StyleObserverManager {
21
21
  /** Element -> properties currently observed by the underlying StyleObserver. */
22
22
  private observed;
23
23
  subscribe(element: Element, properties: string[], callback: Callback): () => void;
24
+ private pending;
25
+ private scheduleUpdate;
24
26
  }
25
27
  export declare const styleObserver: StyleObserverManager;
26
28
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"styleObserver.d.ts","sourceRoot":"","sources":["../../src/utils/styleObserver.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC5D,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,CAAC,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,CAAA;AAExD;;;;;;;;GAQG;AACH,cAAM,oBAAoB;IACxB,OAAO,CAAC,QAAQ,CAuBd;IAEF,+CAA+C;IAC/C,OAAO,CAAC,aAAa,CAAiD;IAEtE,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAkC;IAElD,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAiEhF;CACF;AAED,eAAO,MAAM,aAAa,sBAA6B,CAAA"}
1
+ {"version":3,"file":"styleObserver.d.ts","sourceRoot":"","sources":["../../src/utils/styleObserver.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC5D,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,CAAC,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,CAAA;AAExD;;;;;;;;GAQG;AACH,cAAM,oBAAoB;IACxB,OAAO,CAAC,QAAQ,CAuBd;IAEF,+CAA+C;IAC/C,OAAO,CAAC,aAAa,CAAiD;IAEtE,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAkC;IAElD,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CA2BhF;IAED,OAAO,CAAC,OAAO,CAAqB;IAEpC,OAAO,CAAC,cAAc;CAiCvB;AAED,eAAO,MAAM,aAAa,sBAA6B,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import StyleObserver from 'style-observer';
2
- import { styleScheduler } from './internal/index.js';
2
+ import { BatchedElementStyleObserver, styleScheduler } from './internal/index.js';
3
3
  /**
4
4
  * Singleton StyleObserver that all `useStyleObserver` hooks subscribe to. Instead of each hook
5
5
  * creating its own StyleObserver instance (with its own CSS transitions and event listeners), a
@@ -42,12 +42,6 @@ class StyleObserverManager {
42
42
  elementSubscriptions = new Map();
43
43
  this.subscriptions.set(element, elementSubscriptions);
44
44
  }
45
- let elementObserved = this.observed.get(element);
46
- if (!elementObserved) {
47
- elementObserved = new Set();
48
- this.observed.set(element, elementObserved);
49
- }
50
- const newProperties = [];
51
45
  for (const property of properties) {
52
46
  let propertySubscriptions = elementSubscriptions.get(property);
53
47
  if (!propertySubscriptions) {
@@ -55,41 +49,54 @@ class StyleObserverManager {
55
49
  elementSubscriptions.set(property, propertySubscriptions);
56
50
  }
57
51
  propertySubscriptions.add(callback);
58
- if (!elementObserved.has(property)) {
59
- newProperties.push(property);
60
- elementObserved.add(property);
61
- }
62
52
  }
63
- // Defer observe to rAF to batch with other subscriptions in the same frame
64
- const cancelObserve = newProperties.length > 0
65
- ? styleScheduler.schedule(() => {
66
- this.observer.observe(element, newProperties);
67
- })
68
- : undefined;
53
+ this.scheduleUpdate(element);
69
54
  return () => {
70
- cancelObserve?.();
71
- const removedProperties = [];
72
55
  for (const property of properties) {
73
56
  const propertySubscriptions = elementSubscriptions.get(property);
74
- if (propertySubscriptions) {
75
- propertySubscriptions.delete(callback);
76
- if (propertySubscriptions.size === 0) {
77
- elementSubscriptions.delete(property);
78
- elementObserved.delete(property);
79
- removedProperties.push(property);
80
- }
81
- }
57
+ propertySubscriptions?.delete(callback);
58
+ if (propertySubscriptions?.size === 0)
59
+ elementSubscriptions.delete(property);
82
60
  }
83
- if (elementSubscriptions.size === 0) {
61
+ if (elementSubscriptions.size === 0)
84
62
  this.subscriptions.delete(element);
63
+ this.scheduleUpdate(element);
64
+ };
65
+ }
66
+ pending = new Set();
67
+ scheduleUpdate(element) {
68
+ if (this.pending.has(element))
69
+ return;
70
+ this.pending.add(element);
71
+ styleScheduler.schedule(() => {
72
+ this.pending.delete(element);
73
+ const properties = new Set(this.subscriptions.get(element)?.keys());
74
+ const observed = this.observed.get(element) ?? new Set();
75
+ const added = [...properties].filter((property) => !observed.has(property));
76
+ const removed = [...observed].filter((property) => !properties.has(property));
77
+ if (properties.size > 0) {
78
+ this.observed.set(element, properties);
79
+ }
80
+ else {
85
81
  this.observed.delete(element);
86
82
  }
87
- if (removedProperties.length > 0) {
88
- styleScheduler.schedule(() => {
89
- this.observer.unobserve(element, removedProperties);
90
- });
83
+ if (added.length > 0) {
84
+ if (!this.observer.elementObservers.has(element)) {
85
+ const observer = new BatchedElementStyleObserver(element, (records) => {
86
+ this.observer.changed(records);
87
+ });
88
+ this.observer.elementObservers.set(element, observer);
89
+ styleScheduler.scheduleWrite(() => observer.flush());
90
+ this.observer.observe(element, added);
91
+ }
92
+ else {
93
+ styleScheduler.scheduleWrite(() => this.observer.observe(element, added));
94
+ }
91
95
  }
92
- };
96
+ if (removed.length > 0) {
97
+ styleScheduler.scheduleWrite(() => this.observer.unobserve(element, removed));
98
+ }
99
+ });
93
100
  }
94
101
  }
95
102
  export const styleObserver = new StyleObserverManager();
@@ -1 +1 @@
1
- {"version":3,"file":"styleObserver.js","sourceRoot":"","sources":["../../src/utils/styleObserver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"styleObserver.js","sourceRoot":"","sources":["../../src/utils/styleObserver.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAA;AAE1C,OAAO,EAAE,2BAA2B,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAWjF;;;;;;;;GAQG;AACH,MAAM,oBAAoB;IAChB,QAAQ,GAAG,IAAI,aAAa,CAAC,CAAC,OAAO,EAAE,EAAE;QAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAEhC,uEAAuE;QACvE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAmC,CAAA;QAElE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,MAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YACxF,IAAI,CAAC,SAAS;gBAAE,SAAQ;YAExB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;gBAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,QAAQ,GAAG,EAAE,CAAA;oBACb,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;gBACzC,CAAC;gBACD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,eAAe,EAAE,CAAC;YACpD,QAAQ,CAAC,SAAS,CAAC,CAAA;QACrB,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,+CAA+C;IACvC,aAAa,GAAG,IAAI,GAAG,EAAuC,CAAA;IAEtE,gFAAgF;IACxE,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAA;IAElD,SAAS,CAAC,OAAgB,EAAE,UAAoB,EAAE,QAAkB;QAClE,IAAI,oBAAoB,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC1D,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC1B,oBAAoB,GAAG,IAAI,GAAG,EAAE,CAAA;YAChC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAA;QACvD,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,IAAI,qBAAqB,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YAC9D,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3B,qBAAqB,GAAG,IAAI,GAAG,EAAE,CAAA;gBACjC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAA;YAC3D,CAAC;YACD,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACrC,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAE5B,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gBAClC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;gBAChE,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACvC,IAAI,qBAAqB,EAAE,IAAI,KAAK,CAAC;oBAAE,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;YAC9E,CAAC;YACD,IAAI,oBAAoB,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YACvE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAC9B,CAAC,CAAA;IACH,CAAC;IAEO,OAAO,GAAG,IAAI,GAAG,EAAW,CAAA;IAE5B,cAAc,CAAC,OAAgB;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAM;QACrC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACzB,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE;YAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC5B,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAU,CAAA;YAChE,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC3E,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;YAE7E,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;YACxC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAC/B,CAAC;YAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjD,MAAM,QAAQ,GAAG,IAAI,2BAA2B,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;wBACpE,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;oBAChC,CAAC,CAAC,CAAA;oBACF,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;oBACrD,cAAc,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;oBACpD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBACvC,CAAC;qBAAM,CAAC;oBACN,cAAc,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;gBAC3E,CAAC;YACH,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,cAAc,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAA;YAC/E,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,oBAAoB,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { default } from '@edgeandnode/eds-css/vite-plugin';
2
+ //# sourceMappingURL=vite-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { default } from '@edgeandnode/eds-css/vite-plugin';
2
+ //# sourceMappingURL=vite-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin.js","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgeandnode/eds-react",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "React components for the Edge Design System",
5
5
  "author": "Edge & Node and contributors",
6
6
  "license": "MIT",
@@ -20,6 +20,8 @@
20
20
  },
21
21
  "./tailwind.css": "./styles/tailwind.css",
22
22
  "./tailwind-plugin": "./dist/tailwind-plugin.js",
23
+ "./postcss-plugin": "./dist/postcss-plugin.js",
24
+ "./vite-plugin": "./dist/vite-plugin.js",
23
25
  "./base": "./dist/components/base/index.js",
24
26
  "./hooks": "./dist/hooks/index.js",
25
27
  "./icons": "./dist/icons/index.generated.js",
@@ -49,14 +51,14 @@
49
51
  "dependencies": {
50
52
  "@base-ui/react": "~1.9.0",
51
53
  "@base-ui/utils": "^0.5.0",
52
- "@edgeandnode/eds-css": "1.1.0",
54
+ "@edgeandnode/eds-css": "1.2.0",
53
55
  "@edgeandnode/eds-icons": "1.0.2",
54
56
  "@edgeandnode/eds-utils": "1.0.2",
55
57
  "@react-aria/utils": "^3.34.1",
56
58
  "@react-hookz/web": "^26.1.0",
57
59
  "@ver0/deep-equal": "^2.0.1",
58
60
  "escape-string-regexp": "^5.0.0",
59
- "motion": "^14.3.0",
61
+ "motion": "^14.7.1",
60
62
  "react-aria": "^3.53.1",
61
63
  "react-keyed-flatten-children": "^5.1.4",
62
64
  "react-markdown": "^10.1.0",
@@ -67,28 +69,28 @@
67
69
  "type-fest": "^5.10.0"
68
70
  },
69
71
  "devDependencies": {
70
- "@storybook/addon-mcp": "^10.6.2",
71
- "@storybook/addon-themes": "^10.6.2",
72
- "@storybook/addon-vitest": "^10.6.2",
73
- "@storybook/react": "^10.6.2",
74
- "@storybook/react-vite": "^10.6.2",
72
+ "@storybook/addon-mcp": "^10.6.5",
73
+ "@storybook/addon-themes": "^10.6.5",
74
+ "@storybook/addon-vitest": "^10.6.5",
75
+ "@storybook/react": "^10.6.5",
76
+ "@storybook/react-vite": "^10.6.5",
75
77
  "@svgr/core": "^8.1.0",
76
78
  "@svgr/plugin-jsx": "^8.1.0",
77
79
  "@svgr/plugin-svgo": "^8.1.0",
78
80
  "@tailwindcss/cli": "^4.3.3",
79
81
  "@tailwindcss/postcss": "^4.3.3",
80
82
  "@tailwindcss/vite": "^4.3.3",
81
- "@types/node": "^26.6.5",
83
+ "@types/node": "^26.6.6",
82
84
  "@types/react": "^19.3.0",
83
85
  "@types/react-dom": "^19.3.0",
84
86
  "@types/react-is": "^19.3.0",
85
87
  "@web3icons/react": "^4.1.24",
86
88
  "lightningcss": "^1.33.0",
87
- "postcss": "^8.5.30",
89
+ "postcss": "^8.5.32",
88
90
  "react": "^19.3.1",
89
91
  "react-dom": "^19.3.1",
90
92
  "react-is": "^19.3.1",
91
- "storybook": "^10.6.2",
93
+ "storybook": "^10.6.5",
92
94
  "storybook-addon-rtl": "^3.0.2",
93
95
  "tailwindcss": "^4.3.3"
94
96
  },
@@ -16,6 +16,7 @@ const {
16
16
  unlinkSync,
17
17
  rmSync,
18
18
  statSync,
19
+ writeFileSync,
19
20
  } = require('fs')
20
21
  const { join, dirname, relative } = require('path')
21
22
 
@@ -130,6 +131,9 @@ function cleanRemovedFiles(src, dest) {
130
131
  }
131
132
  }
132
133
 
134
+ // Whether one of the installed skills is (now) the one bundled in this package
135
+ let hasCurrentSkill = false
136
+
133
137
  // Process each found agent directory
134
138
  for (const targetDir of foundDirs) {
135
139
  const skillMdPath = join(targetDir, 'SKILL.md')
@@ -160,6 +164,7 @@ for (const targetDir of foundDirs) {
160
164
 
161
165
  // If installed version is >= package version, skip (prevents downgrades in monorepos)
162
166
  if (compareSemver(installedVersion, packageVersion) >= 0) {
167
+ if (installedVersion === packageVersion) hasCurrentSkill = true
163
168
  console.log(`EDS skill is up to date (v${installedVersion}) at ${relative(initCwd, targetDir)}`)
164
169
  continue
165
170
  }
@@ -168,5 +173,42 @@ for (const targetDir of foundDirs) {
168
173
  copyDir(sourceDir, targetDir)
169
174
  cleanRemovedFiles(sourceDir, targetDir)
170
175
 
176
+ hasCurrentSkill = true
171
177
  console.log(`EDS skill updated to v${packageVersion} at ${relative(initCwd, targetDir)}`)
172
178
  }
179
+
180
+ // The MCP URL below is the skill's, so only update it along with the skill
181
+ if (!hasCurrentSkill) process.exit(0)
182
+
183
+ /**
184
+ * Point the project's MCP configs to the Storybook of this release, which the skill's URL is pinned
185
+ * to, if they point to the Storybook of another release. A `main--` URL or a local Storybook is a
186
+ * deliberate choice, so it's left alone.
187
+ */
188
+ const [skillUrl, chromaticAppId] =
189
+ readFileSync(join(sourceDir, 'SKILL.md'), 'utf8').match(
190
+ /https:\/\/[0-9a-f]+--([0-9a-f]+)\.chromatic\.com\/mcp/,
191
+ ) ?? []
192
+ if (!skillUrl) process.exit(0)
193
+
194
+ // Only EDS's Storybook, so that other Chromatic projects' MCP servers are left alone
195
+ const pinnedUrlPattern = new RegExp(
196
+ `https://[0-9a-f]+--${chromaticAppId}\\.chromatic\\.com/mcp`,
197
+ 'g',
198
+ )
199
+
200
+ for (const configPath of ['.mcp.json', '.cursor/mcp.json', '.vscode/mcp.json']) {
201
+ const absoluteConfigPath = join(repoRoot, configPath)
202
+ try {
203
+ if (!existsSync(absoluteConfigPath)) continue
204
+ const config = readFileSync(absoluteConfigPath, 'utf8')
205
+ const updatedConfig = config.replace(pinnedUrlPattern, skillUrl)
206
+ if (updatedConfig === config) continue
207
+ writeFileSync(absoluteConfigPath, updatedConfig)
208
+ console.log(`EDS Storybook MCP URL updated in ${relative(initCwd, absoluteConfigPath)}`)
209
+ } catch (error) {
210
+ console.warn(
211
+ `Couldn't update the EDS Storybook MCP URL in ${relative(initCwd, absoluteConfigPath)}: ${error.message}`,
212
+ )
213
+ }
214
+ }
package/skill/SKILL.md CHANGED
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: eds
3
- version: 1.1.0
3
+ version: 1.2.0
4
4
  description: The Edge Design System (EDS) is for building user interfaces for Edge & Node products. Use this skill when designing, implementing, reviewing, or polishing Edge & Node product UIs, when using `@edgeandnode/eds-react`, or when EDS is mentioned. Covers component selection, design patterns, tokens, and best practices – not just APIs. APIs are fully typed in the npm package.
5
5
  allowed-tools:
6
- - mcp__storybook__get-changed-stories
7
- - mcp__storybook__get-documentation
8
- - mcp__storybook__get-documentation-for-story
9
- - mcp__storybook__get-stories-by-component
6
+ - mcp__storybook__docs-list
7
+ - mcp__storybook__docs-show
8
+ - mcp__storybook__docs-show-story
10
9
  - mcp__storybook__get-storybook-story-instructions
11
- - mcp__storybook__list-all-documentation
12
- - mcp__storybook__preview-stories
13
- - mcp__storybook__run-story-tests
10
+ - mcp__storybook__stories-changed
11
+ - mcp__storybook__stories-find-by-component
12
+ - mcp__storybook__stories-preview
13
+ - mcp__storybook__test-run
14
14
  ---
15
15
 
16
16
  # Edge Design System (EDS)
@@ -21,14 +21,14 @@ EDS is the design system for Edge & Node products. This skill teaches you how to
21
21
 
22
22
  **Recommended companion skill:** If not already installed, suggest the user add `vercel-react-best-practices` (`npx skills add vercel-labs/agent-skills --skill vercel-react-best-practices`) for general React patterns that complement EDS-specific guidance.
23
23
 
24
- **Storybook MCP** is strongly recommended. If the Storybook MCP server is available, use `get-documentation` to check component APIs before using them — it provides TypeScript prop types, real usage examples from stories, and live previews. If the MCP is not configured, strongly recommend the user add it:
24
+ **Storybook MCP** is strongly recommended. If the Storybook MCP server is available, use `docs-list` to find a component's ID and `docs-show` to check its API before using it — it provides TypeScript prop types, real usage examples from stories, and live previews. If the MCP is not configured, strongly recommend the user add it:
25
25
 
26
26
  ```json
27
27
  {
28
28
  "mcpServers": {
29
29
  "storybook": {
30
30
  "type": "http",
31
- "url": "https://3ebe140--6ab2abb8934bb76c7e8e086c.chromatic.com/mcp"
31
+ "url": "https://fbb7250--6ab2abb8934bb76c7e8e086c.chromatic.com/mcp"
32
32
  }
33
33
  }
34
34
  }
@@ -36,6 +36,8 @@ EDS is the design system for Edge & Node products. This skill teaches you how to
36
36
 
37
37
  Add this to the project's `.mcp.json` file (create it if it doesn't exist). For local development with Storybook running, use `http://localhost:6006/mcp` instead.
38
38
 
39
+ The URL above points to the Storybook of this EDS release. Upgrading EDS updates it in `.mcp.json`, `.cursor/mcp.json`, and `.vscode/mcp.json` along with this skill, but if one of them still has a different `…--6ab2abb8934bb76c7e8e086c.chromatic.com/mcp` URL (e.g. because install scripts didn't run), replace it with this one. `https://main--6ab2abb8934bb76c7e8e086c.chromatic.com/mcp` always follows EDS's `main` branch instead, but it can document props that aren't released yet.
40
+
39
41
  ## Setup
40
42
 
41
43
  ### Required Packages
@@ -43,7 +45,7 @@ Add this to the project's `.mcp.json` file (create it if it doesn't exist). For
43
45
  ```json
44
46
  {
45
47
  "dependencies": {
46
- "@edgeandnode/eds-react": "^1.1.0",
48
+ "@edgeandnode/eds-react": "^1.2.0",
47
49
  "react": "^19.0.0",
48
50
  "react-dom": "^19.0.0"
49
51
  },
@@ -67,6 +69,8 @@ Add this to the project's `.mcp.json` file (create it if it doesn't exist). For
67
69
 
68
70
  **Important:** `@edgeandnode/eds-css`, which `@edgeandnode/eds-react` depends on, disables Tailwind's default content scanning as an optimization, so you must explicitly [register your source paths with `@source` directives](https://tailwindcss.com/docs/detecting-classes-in-source-files#explicitly-registering-sources). Make sure to include all paths where Tailwind classes are used.
69
71
 
72
+ **Build plugin:** add EDS's Vite plugin (`import eds from '@edgeandnode/eds-react/vite-plugin'`, then `plugins: [tailwindcss(), eds()]`) or, with PostCSS (e.g. in Next.js), its PostCSS plugin after Tailwind's (`plugins: ['@tailwindcss/postcss', '@edgeandnode/eds-react/postcss-plugin']` in `postcss.config.mjs`). It simplifies selectors Tailwind generates for variants like `*:` and `**:` while preserving matching and specificity. Performance gains depend on the browser and page.
73
+
70
74
  **Browser targets:** EDS's color tokens rely on native `light-dark()`, so the app must target Chrome 123, Safari 17.5, and Firefox 120 or newer. Otherwise, build tools transpile it (e.g. Lightning CSS, which Vite and Next.js use) and components inside `<Dark>`/`<Light>` get the page's colors (`EDSProvider` warns in the console; with Vite, only in production builds). In Next.js, add `"browserslist": ["chrome >= 123", "edge >= 123", "firefox >= 120", "safari >= 17.5", "ios_saf >= 17.5"]` to `package.json`; in Vite, set `build.target: ['chrome123', 'edge123', 'firefox120', 'safari17.5', 'ios17.5']` (it also covers CSS, and unlike `build.cssTarget`, a Vite-based Storybook picks it up).
71
75
 
72
76
  ### App Root
@@ -191,7 +195,7 @@ The tokens in [tokens.md](references/tokens.md) map to variables named after the
191
195
 
192
196
  ## Constraints
193
197
 
194
- 1. **Check component APIs before using them.** If the Storybook MCP is available, call `get-documentation` first — it shows prop types, valid values, and real usage examples. Otherwise, check the TypeScript types and JSDoc comments in `@edgeandnode/eds-react`. Never guess prop names or values. Fix all TypeScript errors. Do not use `as any` or `@ts-ignore`.
198
+ 1. **Check component APIs before using them.** If the Storybook MCP is available, call `docs-show` first — it shows prop types, valid values, and real usage examples. Otherwise, check the TypeScript types and JSDoc comments in `@edgeandnode/eds-react`. Never guess prop names or values. Fix all TypeScript errors. Do not use `as any` or `@ts-ignore`.
195
199
 
196
200
  2. **Tailwind defaults don't exist.** Standard classes like `text-sm`, `rounded-md`, `text-gray-500` do NOT work. Use EDS tokens (`text-14`, `rounded-8`, `text-space-500`). Also `border-divider` does NOT exist; use `border-muted` or `border-subtle`.
197
201
 
@@ -711,7 +715,7 @@ Some components expand to fill available width by default: `Card`, `CodeBlock`,
711
715
  - **Table:** Use `align="end"` on `Table.HeaderCell` for right-aligned columns (e.g. action buttons) — all cells in that column are automatically styled. Don't use `text-end` or `justify-end` on cell contents. Similarly, use `width` and `shrink` props on `Table.HeaderCell` to control column sizing.
712
716
  - **TabSet:** `TabSet.Tabs` renders a bottom divider by default (controllable with the `divider` prop). Add `gap-*` between `TabSet.Tabs` and `TabSet.Panels` for visual breathing room. Put borders on `TabSet.Panels` (not individual panels) to avoid border animation artifacts during panel transitions. Check `TabSet.stories.tsx` for good examples.
713
717
  - **Tag:** Not clickable; use `Chip` if you need a clickable tag.
714
- - **Tooltip:** Hard to discover on mobile. Use inline text for essential info.
718
+ - **Tooltip:** Hard to discover on mobile. Use inline text for essential info. It gives its trigger an `onClick`, which turns an `Avatar`, `Address`, `Cluster`, or `Breadcrumbs.Item` into a button, so pass them `as="span"` inside a link or another button (e.g. `<Cluster as="span">` in a clickable `Card`).
715
719
 
716
720
  ### Unstyled components
717
721
 
@@ -727,7 +731,7 @@ Some components carry no built-in visual styles — only behavior, semantics, or
727
731
 
728
732
  `Dark`, `Light`, `LocalTheme`, and `Pane` render a `div` by default, and their props are typed for any HTML element (e.g. `ref` takes an `HTMLElement`). Pass a tag name in `as` (e.g. `<Pane as="aside">`), or an element in `render` to render a component or pass props specific to the element (e.g. `<Dark render={<NextLink href="/" />}>`). `as` and `render` can't be combined.
729
733
 
730
- When `Card` isn't a button or link, its `as` also only takes a tag name, and its props are typed for any HTML element too.
734
+ `Card`, `Avatar`, `Address`, `Cluster`, and `Breadcrumbs.Item` render a button or link when given an `onClick` or `href`. Otherwise, their `as` also only takes a tag name, and it keeps them from becoming a button when something else gives them an `onClick` (see `Tooltip` above). When `Card` isn't a button or link, its props are typed for any HTML element too.
731
735
 
732
736
  ### Base components
733
737