@innovaccer/design-system 5.0.0-29 → 5.0.0-30

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/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ## 4.28.0-1 (2026-08-18)
2
+
3
+ ### Highlights
4
+
5
+ - Support for scoped CSS, letting consumers isolate design-system styles from the host application's global stylesheet.
6
+
7
+ ### Breaking changes
8
+
9
+ NA
10
+
11
+ ### Migration guide
12
+
13
+ NA
14
+
15
+ ### Deprecations
16
+
17
+ NA
18
+
19
+ ### Improvements
20
+
21
+ - style(css): add support for scoped css (fcedea2d5)
22
+
23
+ ---
24
+
1
25
  ## 4.27.0 (2026-08-04)
2
26
 
3
27
  ### Highlights
@@ -0,0 +1,145 @@
1
+ # Scoped stylesheet
2
+
3
+ An additional consumer entry built alongside the default `dist/index.css`. Identical rules,
4
+ wrapped in `@scope ([data-mds-root])`, so MDS styles only apply inside containers the host
5
+ app opts in to — useful when MDS runs next to another stylesheet (Tailwind, a legacy global
6
+ sheet, another design system) in the same document.
7
+
8
+ - Output: `css/dist/mds-scoped.css`
9
+ - Import: `@innovaccer/design-system/css/scoped` or `…/css/dist/mds-scoped.css`
10
+ - Build: `npm run build-css` (gulp, builds both bundles) or `npm run build-css-scoped`
11
+
12
+ The default `dist/index.css` bundle is unchanged — this is purely additive.
13
+
14
+ ## Usage
15
+
16
+ ```html
17
+ <div data-mds-root>
18
+ <!-- MDS components -->
19
+ </div>
20
+ ```
21
+
22
+ Everything outside `[data-mds-root]` is untouched by MDS, and MDS components inside it are
23
+ unaffected by the host app's global styles that would otherwise reach them.
24
+
25
+ The scope root is yours to style — MDS declares nothing on it. If you put `data-mds-root` on a
26
+ custom element, remember that custom elements default to `display: inline`, so give it a
27
+ `display` of its own:
28
+
29
+ ```css
30
+ ui-shell-app {
31
+ display: block;
32
+ }
33
+ ```
34
+
35
+ ## How the build composes it
36
+
37
+ `scripts/build-scoped.mjs` reads the same sources, in the same order, as the default build
38
+ (both import the list from `scripts/css-sources.cjs`, so they cannot drift), then:
39
+
40
+ 1. **Hoists global-namespace at-rules** — `@keyframes`, `@font-face`, `@property` and
41
+ `@counter-style` above the `@scope` block. Their names are document-global and are not
42
+ scopable; leaving them inside would silently drop them. The build throws if one is nested
43
+ inside another at-rule, where the hoist cannot reach it.
44
+ 2. **Remaps `:root` / `html` / `body` / `:host` to `:scope`** so design tokens attach to the
45
+ scope root. Without this, every custom-property reference in the bundle resolves to nothing.
46
+ 3. **Adds a root-anchored variant of every selector** — `.Backdrop` becomes
47
+ `.Backdrop, :scope.Backdrop`. See *Overlays* below.
48
+ 4. **Wraps the result** in `@scope ([data-mds-root]) { … }`.
49
+
50
+ Step 3 costs about +28% in raw bytes (~80 KB, considerably less gzipped).
51
+
52
+ Nothing is declared on the scope root itself. A `[data-mds-root]` element is consumer
53
+ markup, so any default MDS set there would compete with the consumer's own layout.
54
+
55
+ ## Overlays
56
+
57
+ Modal, Sidesheet, FullscreenModal, Backdrop, Popover, Tooltip, Dropdown, Menu and the
58
+ Listbox drag ghost all render through `ReactDOM.createPortal` into `document.body` — outside
59
+ the consumer's `[data-mds-root]`. Without special handling they would receive neither
60
+ component rules nor tokens, and render completely unstyled.
61
+
62
+ Inside `@scope`, a rule like `.Backdrop` is implicitly `:scope .Backdrop`, so it matches
63
+ **descendants of a scope root only**. Those portaled elements therefore have to be scope
64
+ roots in their own right, and there is no MDS-owned ancestor to hang that on. So the build
65
+ adds them to the prelude directly, targeting markup the components *already* render:
66
+
67
+ ```css
68
+ @scope (
69
+ [data-mds-root], /* your opt-in container */
70
+ body > .Overlay-wrapper:has([data-layer]), /* Modal, Sidesheet, FullscreenModal */
71
+ body > [data-test='DesignSystem-Popover'], /* Popover, Tooltip, Dropdown, Menu, … */
72
+ body > [data-test='DesignSystem-Backdrop'], /* Backdrop */
73
+ body > .Listbox-item--draggable /* Listbox drag ghost */
74
+ )
75
+ ```
76
+
77
+ Every popper-based component shares one root — `Popover` renders the popup element itself and
78
+ Tooltip/Dropdown/Menu all go through it — so a single selector covers them all.
79
+
80
+ Each selector is qualified so it cannot collide with a host app's own class names:
81
+
82
+ - **`body >`** — all of these land as direct children of `<body>`, so a colliding host class
83
+ would have to be at body level too.
84
+ - **`:has([data-layer])`** — `data-layer` is an MDS-only attribute present on all five portal
85
+ roots. `.Overlay-wrapper` is a generic enough name that a host app could plausibly reuse it,
86
+ so the class alone is not enough. It matches a *descendant* rather than a child because Modal
87
+ wraps its container in `OutsideClick` when `backdropClose` is set.
88
+ - **`data-test='DesignSystem-*'`** — already namespaced.
89
+
90
+ The root-anchored selector variants from step 3 are what let those roots style *themselves*:
91
+ `.Backdrop` alone would only match descendants. Because *every* rule gets a variant, all rules
92
+ matching a given scope root are bumped by the same `:scope` (0,1,0), so relative specificity —
93
+ and therefore the cascade between MDS rules — is preserved.
94
+
95
+ `css/scripts/portal-roots.cjs` is the single source of truth for this list, shared with
96
+ `core/utils/__tests__/scopedPortalRoots.test.tsx`. That test renders each overlay and asserts
97
+ the selectors still match, so if a component ever stops rendering one of these hooks the build
98
+ fails loudly instead of silently shipping unstyled overlays.
99
+
100
+ ### No component changes required
101
+
102
+ This is the reason the prelude keys off existing markup rather than a dedicated attribute:
103
+ nothing in `core/` changes, so **the scoped stylesheet can be updated independently of the
104
+ library version**. Consumers swap the CSS file without rebuilding or upgrading, and it works
105
+ against releases already in the wild.
106
+
107
+ ## Custom scope selectors
108
+
109
+ `@scope`'s prelude is a forgiving selector list, so attribute and class patterns work:
110
+
111
+ ```bash
112
+ MDS_SCOPE_SELECTOR='[data-mds-root], [class^="ui-"][class$="-app"]' npm run build-css-scoped
113
+ MDS_SCOPE_OUTPUT='ui-apps.css' MDS_SCOPE_SELECTOR='ui-shell-app, ui-admin-app' npm run build-css-scoped
114
+ ```
115
+
116
+ One selector list in a single `@scope` block covers many hosts — you do not need a stylesheet
117
+ per app.
118
+
119
+ `MDS_SCOPE_SELECTOR` replaces only the *consumer* part of the prelude. The portal-root
120
+ selectors are always appended, so MDS's overlays stay scoped whatever you scope on. The build
121
+ logs the final prelude it used.
122
+
123
+ CSS has **no tag-name wildcard**, so a pattern like `ui-*-app` cannot be expressed as a
124
+ selector: `^=` / `$=` / `*=` match attribute *values*, and a tag name is not an attribute.
125
+ For custom elements following a naming convention, either enumerate the tags in
126
+ `MDS_SCOPE_SELECTOR`, or have the host stamp `data-mds-root` onto matching elements at
127
+ runtime (a `MutationObserver` plus `/^ui-.*-app$/.test(el.tagName.toLowerCase())`).
128
+
129
+ ## Caveats
130
+
131
+ - **Browser support**: `@scope` requires Chrome/Edge 118+, Safari 17.4+, Firefox 128+. There
132
+ is no fallback — an older browser drops the whole stylesheet as an unknown at-rule and
133
+ renders MDS unstyled. Serve `dist/index.css` to browsers you still support.
134
+ - **`@keyframes` names stay global.** They are hoisted out of `@scope`, so animation names
135
+ still collide with the host app's. `Spinner`'s were renamed to `mds-spin` / `mds-rotate`;
136
+ generic ones such as `fadeIn`, `fadeOut` and `shimmer` remain exposed.
137
+ - **Portaled overlays get base tokens**, not per-root token overrides: a themed
138
+ `[data-mds-root]` does not affect overlays, which are scope roots of their own under
139
+ `<body>`. They are deliberately not re-parented into the app's scope root, because a
140
+ `transform` / `filter` / `contain` on an ancestor there would become the containing block
141
+ and break `position: fixed` overlays. Declare token overrides on `:root` so both the
142
+ in-tree components and the body-level overlays pick them up.
143
+ - **The drag ghost has the weakest qualifier.** No `data-test` exists on it, so
144
+ `body > .Listbox-item--draggable` is all that is available. Worth tightening with a
145
+ `data-test` next time component changes ship.
@@ -10138,7 +10138,7 @@ body {
10138
10138
  }
10139
10139
  }
10140
10140
 
10141
- @keyframes rotate {
10141
+ @keyframes mds-rotate {
10142
10142
  0% {
10143
10143
  transform: rotate(0deg);
10144
10144
  }
@@ -10147,7 +10147,7 @@ body {
10147
10147
  }
10148
10148
  }
10149
10149
 
10150
- @keyframes spin {
10150
+ @keyframes mds-spin {
10151
10151
  0% {
10152
10152
  stroke-dasharray: 1, 200;
10153
10153
  stroke-dashoffset: 0;
@@ -10163,7 +10163,7 @@ body {
10163
10163
  }
10164
10164
 
10165
10165
  .Spinner {
10166
- animation: rotate 2s linear infinite;
10166
+ animation: mds-rotate 2s linear infinite;
10167
10167
  }
10168
10168
 
10169
10169
  .Spinner--xsmall {
@@ -10190,7 +10190,7 @@ body {
10190
10190
  stroke-linecap: round;
10191
10191
  stroke-dasharray: 1 200;
10192
10192
  stroke-dashoffset: 0;
10193
- animation: spin 1.5s ease-in-out infinite;
10193
+ animation: mds-spin 1.5s ease-in-out infinite;
10194
10194
  }
10195
10195
 
10196
10196
  .Circle--primary {