@salt-ds/styles 0.2.1 → 0.3.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/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # @salt-ds/styles
2
+
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 27c4338: This feature is in-development, for exploration and feedback only.
8
+
9
+ Introduce a context‑driven API for injecting CSS class names into Salt components based on their props, and optionally stripping implementation‑only props before forwarding.
10
+
11
+ _Status_
12
+ Non‑breaking for existing Salt consumers
13
+ Experimental and incomplete — interfaces and behavior may change without notice
14
+
15
+ **Note to JPM employees**
16
+ Use only in non‑production codebases, or with prior permission from the Salt engineering team
17
+ What’s included
18
+
19
+ - `ClassNameInjectionProvider` — supplies a registry of class injectors via React context
20
+ - `useClassNameInjection(component, props)`
21
+ - computes additional classes via registered injectors
22
+ - merges them with any className provided at the call site
23
+ - removes internal/derived props (declared by each injector) before forwarding
24
+ - `registerClassInjector(registry, component, keys, injector)` — registers per‑component injection rules
25
+
26
+ _Documentation_
27
+ Full documentation will follow once the API is stabilized; for now, consider this API private and subject to change.
28
+
29
+ ## 0.2.1
30
+
31
+ ### Patch Changes
32
+
33
+ - f7fcbd11: Fixed issue where components are not injecting their styles.
34
+
35
+ ## 0.2.0
36
+
37
+ ### Minor Changes
38
+
39
+ - 02815995: Updated `useComponentCssInjection` to not inject styles when configured by the SaltProvider.
40
+
41
+ ## 0.1.2
42
+
43
+ ### Patch Changes
44
+
45
+ - 45eaeeb5: Fix `useInsertionEffect` not found error bundled by Webpack
46
+
47
+ ## 0.1.1
48
+
49
+ ### Patch Changes
50
+
51
+ - abfc4364: Corrected the minimum supported version of React. It has been updated to 16.14.0 due to the support for the new [JSX transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)
52
+
53
+ ## 0.1.0
54
+
55
+ ### Minor Changes
56
+
57
+ - d78ff537: Added @salt-ds/styles and @salt-ds/window packages
58
+
59
+ These packages are introduced to support uses of Salt in a desktop application where pop-out elements such as tooltips are rendered into separate windows with no previously added CSS.
60
+
61
+ The insertion point where useComponentCssInjection inserts styles can be controlled via InsertionPointContext
package/dist-cjs/index.js CHANGED
@@ -1,16 +1,18 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var useStyleInjection = require('./use-style-injection/useStyleInjection.js');
6
- var InsertionPointProvider = require('./use-style-injection/InsertionPointProvider.js');
7
3
  var index = require('./style-injection-provider/index.js');
4
+ var InsertionPointProvider = require('./use-style-injection/InsertionPointProvider.js');
5
+ var useStyleInjection = require('./use-style-injection/useStyleInjection.js');
6
+ var useClassNameInjection = require('./useClassNameInjection.js');
8
7
 
9
8
 
10
9
 
11
- exports.useComponentCssInjection = useStyleInjection.useComponentCssInjection;
12
- exports.InsertionPointProvider = InsertionPointProvider.InsertionPointProvider;
13
- exports.useInsertionPoint = InsertionPointProvider.useInsertionPoint;
14
10
  exports.StyleInjectionProvider = index.StyleInjectionProvider;
15
11
  exports.useStyleInjection = index.useStyleInjection;
12
+ exports.InsertionPointProvider = InsertionPointProvider.InsertionPointProvider;
13
+ exports.useInsertionPoint = InsertionPointProvider.useInsertionPoint;
14
+ exports.useComponentCssInjection = useStyleInjection.useComponentCssInjection;
15
+ exports.ClassNameInjectionProvider = useClassNameInjection.ClassNameInjectionProvider;
16
+ exports.registerClassInjector = useClassNameInjection.registerClassInjector;
17
+ exports.useClassNameInjection = useClassNameInjection.useClassNameInjection;
16
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -1,22 +1,17 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var jsxRuntime = require('react/jsx-runtime');
6
4
  var React = require('react');
7
5
 
8
6
  const StyleInjectionContext = React.createContext(true);
9
7
  function useStyleInjection(enableStyleInjection) {
10
8
  const enableStyleInjectionFromContext = React.useContext(StyleInjectionContext);
11
- return enableStyleInjection != null ? enableStyleInjection : enableStyleInjectionFromContext;
9
+ return enableStyleInjection ?? enableStyleInjectionFromContext;
12
10
  }
13
11
  function StyleInjectionProvider(props) {
14
12
  const { value: enableStyleInjectionProp, children } = props;
15
13
  const value = useStyleInjection(enableStyleInjectionProp);
16
- return /* @__PURE__ */ jsxRuntime.jsx(StyleInjectionContext.Provider, {
17
- value,
18
- children
19
- });
14
+ return /* @__PURE__ */ jsxRuntime.jsx(StyleInjectionContext.Provider, { value, children });
20
15
  }
21
16
 
22
17
  exports.StyleInjectionProvider = StyleInjectionProvider;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/style-injection-provider/index.tsx"],"sourcesContent":["import React, { type ReactNode, createContext, useContext } from \"react\";\nexport interface StyleInjectionContextType {\n value?: boolean;\n}\n\nconst StyleInjectionContext = createContext(true);\n\nexport function useStyleInjection(enableStyleInjection?: boolean): boolean {\n const enableStyleInjectionFromContext = useContext(StyleInjectionContext);\n return enableStyleInjection ?? enableStyleInjectionFromContext;\n}\n\nexport interface StyleInjectionProviderProps extends StyleInjectionContextType {\n children: ReactNode;\n}\n\nexport function StyleInjectionProvider(props: StyleInjectionProviderProps) {\n const { value: enableStyleInjectionProp, children } = props;\n const value = useStyleInjection(enableStyleInjectionProp);\n\n return (\n <StyleInjectionContext.Provider value={value}>\n {children}\n </StyleInjectionContext.Provider>\n );\n}\n"],"names":["createContext","useContext","jsx"],"mappings":";;;;;;;AAKA,MAAM,qBAAA,GAAwBA,oBAAc,IAAI,CAAA,CAAA;AAEzC,SAAS,kBAAkB,oBAAyC,EAAA;AACzE,EAAM,MAAA,+BAAA,GAAkCC,iBAAW,qBAAqB,CAAA,CAAA;AACxE,EAAA,OAAO,oBAAwB,IAAA,IAAA,GAAA,oBAAA,GAAA,+BAAA,CAAA;AACjC,CAAA;AAMO,SAAS,uBAAuB,KAAoC,EAAA;AACzE,EAAA,MAAM,EAAE,KAAA,EAAO,wBAA0B,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AACtD,EAAM,MAAA,KAAA,GAAQ,kBAAkB,wBAAwB,CAAA,CAAA;AAExD,EACE,uBAAAC,cAAA,CAAC,sBAAsB,QAAtB,EAAA;AAAA,IAA+B,KAAA;AAAA,IAC7B,QAAA;AAAA,GACH,CAAA,CAAA;AAEJ;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/style-injection-provider/index.tsx"],"sourcesContent":["import { createContext, type ReactNode, useContext } from \"react\";\nexport interface StyleInjectionContextType {\n value?: boolean;\n}\n\nconst StyleInjectionContext = createContext(true);\n\nexport function useStyleInjection(enableStyleInjection?: boolean): boolean {\n const enableStyleInjectionFromContext = useContext(StyleInjectionContext);\n return enableStyleInjection ?? enableStyleInjectionFromContext;\n}\n\nexport interface StyleInjectionProviderProps extends StyleInjectionContextType {\n children: ReactNode;\n}\n\nexport function StyleInjectionProvider(props: StyleInjectionProviderProps) {\n const { value: enableStyleInjectionProp, children } = props;\n const value = useStyleInjection(enableStyleInjectionProp);\n\n return (\n <StyleInjectionContext.Provider value={value}>\n {children}\n </StyleInjectionContext.Provider>\n );\n}\n"],"names":["createContext","useContext","jsx"],"mappings":";;;;;AAKA,MAAM,qBAAA,GAAwBA,oBAAc,IAAI,CAAA;AAEzC,SAAS,kBAAkB,oBAAA,EAAyC;AACzE,EAAA,MAAM,+BAAA,GAAkCC,iBAAW,qBAAqB,CAAA;AACxE,EAAA,OAAO,oBAAA,IAAwB,+BAAA;AACjC;AAMO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,EAAE,KAAA,EAAO,wBAAA,EAA0B,QAAA,EAAS,GAAI,KAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,kBAAkB,wBAAwB,CAAA;AAExD,EAAA,uBACEC,cAAA,CAAC,qBAAA,CAAsB,QAAA,EAAtB,EAA+B,OAC7B,QAAA,EACH,CAAA;AAEJ;;;;;"}
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var jsxRuntime = require('react/jsx-runtime');
6
4
  var React = require('react');
7
5
 
@@ -12,10 +10,7 @@ if (process.env.NODE_ENV !== "production") {
12
10
  function InsertionPointProvider(props) {
13
11
  const { insertionPoint: insertionPointProp, children } = props;
14
12
  const value = React.useMemo(() => insertionPointProp, [insertionPointProp]);
15
- return /* @__PURE__ */ jsxRuntime.jsx(InsertionPointContext.Provider, {
16
- value,
17
- children
18
- });
13
+ return /* @__PURE__ */ jsxRuntime.jsx(InsertionPointContext.Provider, { value, children });
19
14
  }
20
15
  function useInsertionPoint() {
21
16
  const value = React.useContext(InsertionPointContext);
@@ -1 +1 @@
1
- {"version":3,"file":"InsertionPointProvider.js","sources":["../src/use-style-injection/InsertionPointProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext, useMemo } from \"react\";\n\nexport interface InsertionPointContextType {\n insertionPoint: ChildNode | null;\n}\n\nconst InsertionPointContext = createContext<ChildNode | null>(null);\n\nif (process.env.NODE_ENV !== \"production\") {\n InsertionPointContext.displayName = \"InsertionPointContext\";\n}\n\nexport interface InsertionPointProviderProps extends InsertionPointContextType {\n children: ReactNode;\n}\n\nexport function InsertionPointProvider(props: InsertionPointProviderProps) {\n const { insertionPoint: insertionPointProp, children } = props;\n const value = useMemo(() => insertionPointProp, [insertionPointProp]);\n\n return (\n <InsertionPointContext.Provider value={value}>\n {children}\n </InsertionPointContext.Provider>\n );\n}\n\nexport function useInsertionPoint() {\n const value = useContext(InsertionPointContext);\n return value;\n}\n"],"names":["createContext","useMemo","jsx","useContext"],"mappings":";;;;;;;AAMA,MAAM,qBAAA,GAAwBA,oBAAgC,IAAI,CAAA,CAAA;AAElE,IAAI,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AACzC,EAAA,qBAAA,CAAsB,WAAc,GAAA,uBAAA,CAAA;AACtC,CAAA;AAMO,SAAS,uBAAuB,KAAoC,EAAA;AACzE,EAAA,MAAM,EAAE,cAAA,EAAgB,kBAAoB,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AACzD,EAAA,MAAM,QAAQC,aAAQ,CAAA,MAAM,kBAAoB,EAAA,CAAC,kBAAkB,CAAC,CAAA,CAAA;AAEpE,EACE,uBAAAC,cAAA,CAAC,sBAAsB,QAAtB,EAAA;AAAA,IAA+B,KAAA;AAAA,IAC7B,QAAA;AAAA,GACH,CAAA,CAAA;AAEJ,CAAA;AAEO,SAAS,iBAAoB,GAAA;AAClC,EAAM,MAAA,KAAA,GAAQC,iBAAW,qBAAqB,CAAA,CAAA;AAC9C,EAAO,OAAA,KAAA,CAAA;AACT;;;;;"}
1
+ {"version":3,"file":"InsertionPointProvider.js","sources":["../src/use-style-injection/InsertionPointProvider.tsx"],"sourcesContent":["import { createContext, type ReactNode, useContext, useMemo } from \"react\";\n\nexport interface InsertionPointContextType {\n insertionPoint: ChildNode | null;\n}\n\nconst InsertionPointContext = createContext<ChildNode | null>(null);\n\nif (process.env.NODE_ENV !== \"production\") {\n InsertionPointContext.displayName = \"InsertionPointContext\";\n}\n\nexport interface InsertionPointProviderProps extends InsertionPointContextType {\n children: ReactNode;\n}\n\nexport function InsertionPointProvider(props: InsertionPointProviderProps) {\n const { insertionPoint: insertionPointProp, children } = props;\n const value = useMemo(() => insertionPointProp, [insertionPointProp]);\n\n return (\n <InsertionPointContext.Provider value={value}>\n {children}\n </InsertionPointContext.Provider>\n );\n}\n\nexport function useInsertionPoint() {\n const value = useContext(InsertionPointContext);\n return value;\n}\n"],"names":["createContext","useMemo","jsx","useContext"],"mappings":";;;;;AAMA,MAAM,qBAAA,GAAwBA,oBAAgC,IAAI,CAAA;AAElE,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AACzC,EAAA,qBAAA,CAAsB,WAAA,GAAc,uBAAA;AACtC;AAMO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAA,EAAS,GAAI,KAAA;AACzD,EAAA,MAAM,QAAQC,aAAA,CAAQ,MAAM,kBAAA,EAAoB,CAAC,kBAAkB,CAAC,CAAA;AAEpE,EAAA,uBACEC,cAAA,CAAC,qBAAA,CAAsB,QAAA,EAAtB,EAA+B,OAC7B,QAAA,EACH,CAAA;AAEJ;AAEO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,KAAA,GAAQC,iBAAW,qBAAqB,CAAA;AAC9C,EAAA,OAAO,KAAA;AACT;;;;;"}
@@ -1,13 +1,10 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var React = require('react');
6
- var InsertionPointProvider = require('./InsertionPointProvider.js');
7
4
  var index = require('../style-injection-provider/index.js');
5
+ var InsertionPointProvider = require('./InsertionPointProvider.js');
8
6
 
9
- function _interopNamespace(e) {
10
- if (e && e.__esModule) return e;
7
+ function _interopNamespaceDefault(e) {
11
8
  var n = Object.create(null);
12
9
  if (e) {
13
10
  Object.keys(e).forEach(function (k) {
@@ -20,14 +17,16 @@ function _interopNamespace(e) {
20
17
  }
21
18
  });
22
19
  }
23
- n["default"] = e;
20
+ n.default = e;
24
21
  return n;
25
22
  }
26
23
 
27
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
24
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
28
25
 
29
- var _a;
30
- const maybeUseInsertionEffect = (_a = React__namespace["useInsertionEffect".toString()]) != null ? _a : React__namespace.useLayoutEffect;
26
+ const maybeUseInsertionEffect = (
27
+ // biome-ignore lint/suspicious/noExplicitAny: see comment above
28
+ React__namespace["useInsertionEffect".toString()] ?? React__namespace.useLayoutEffect
29
+ );
31
30
  const windowSheetsMap = /* @__PURE__ */ new WeakMap();
32
31
  function useComponentCssInjection({
33
32
  testId,
@@ -37,12 +36,11 @@ function useComponentCssInjection({
37
36
  const styleInjectionEnabled = index.useStyleInjection();
38
37
  const insertionPoint = InsertionPointProvider.useInsertionPoint();
39
38
  maybeUseInsertionEffect(() => {
40
- var _a2, _b;
41
39
  if (!targetWindow || !styleInjectionEnabled) {
42
40
  return;
43
41
  }
44
- const sheetsMap = (_a2 = windowSheetsMap.get(targetWindow)) != null ? _a2 : /* @__PURE__ */ new Map();
45
- const styleMap = (_b = sheetsMap.get(css)) != null ? _b : { styleElement: null, count: 0 };
42
+ const sheetsMap = windowSheetsMap.get(targetWindow) ?? /* @__PURE__ */ new Map();
43
+ const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };
46
44
  if (styleMap.styleElement == null) {
47
45
  styleMap.styleElement = targetWindow.document.createElement("style");
48
46
  styleMap.styleElement.setAttribute("type", "text/css");
@@ -1 +1 @@
1
- {"version":3,"file":"useStyleInjection.js","sources":["../src/use-style-injection/useStyleInjection.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useInsertionPoint } from \"./InsertionPointProvider\";\nimport { useStyleInjection } from \"../style-injection-provider\";\n\n/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any -- Workaround for https://github.com/webpack/webpack/issues/14814#issuecomment-1536757985 */\nconst maybeUseInsertionEffect: typeof React.useLayoutEffect =\n (React as any)[\"useInsertionEffect\".toString()] ?? React.useLayoutEffect;\n/* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */\n\nexport interface UseComponentCssInjection {\n testId?: string;\n css: string;\n window?: Window | null;\n}\n\ntype StyleElementMap = Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n>;\n\n// windowSheetsMap maps window objects to StyleElementMaps\n// A StyleElementMap maps css strings to style element tags\nconst windowSheetsMap = new WeakMap<Window, StyleElementMap>();\n\nexport function useComponentCssInjection({\n testId,\n css,\n window: targetWindow,\n}: UseComponentCssInjection): void {\n const styleInjectionEnabled = useStyleInjection();\n const insertionPoint = useInsertionPoint();\n\n maybeUseInsertionEffect(() => {\n if (!targetWindow || !styleInjectionEnabled) {\n return;\n }\n\n const sheetsMap =\n windowSheetsMap.get(targetWindow) ??\n new Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n >();\n const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };\n\n if (styleMap.styleElement == null) {\n styleMap.styleElement = targetWindow.document.createElement(\"style\");\n styleMap.styleElement.setAttribute(\"type\", \"text/css\");\n styleMap.styleElement.setAttribute(\"data-salt-style\", testId || \"\");\n styleMap.styleElement.textContent = css;\n\n styleMap.count = 1;\n\n targetWindow.document.head.insertBefore(\n styleMap.styleElement,\n insertionPoint || targetWindow.document.head.firstChild\n );\n } else {\n styleMap.styleElement.textContent = css;\n styleMap.count++;\n }\n sheetsMap.set(css, styleMap);\n windowSheetsMap.set(targetWindow, sheetsMap);\n\n return () => {\n const sheetsMap = windowSheetsMap.get(targetWindow);\n const styleMap = sheetsMap?.get(css);\n if (styleMap?.styleElement) {\n styleMap.count--;\n if (styleMap.count < 1) {\n targetWindow.document.head.removeChild(styleMap.styleElement);\n styleMap.styleElement = null;\n sheetsMap?.delete(css);\n }\n }\n };\n }, [testId, css, targetWindow]);\n}\n"],"names":["React","useStyleInjection","useInsertionPoint","_a","sheetsMap","styleMap"],"mappings":"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"}
1
+ {"version":3,"file":"useStyleInjection.js","sources":["../src/use-style-injection/useStyleInjection.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useStyleInjection } from \"../style-injection-provider\";\nimport { useInsertionPoint } from \"./InsertionPointProvider\";\n\n/* Workaround for https://github.com/webpack/webpack/issues/14814#issuecomment-1536757985 */\nconst maybeUseInsertionEffect: typeof React.useLayoutEffect =\n // biome-ignore lint/suspicious/noExplicitAny: see comment above\n (React as any)[\"useInsertionEffect\".toString()] ?? React.useLayoutEffect;\n\nexport interface UseComponentCssInjection {\n testId?: string;\n css: string;\n window?: Window | null;\n}\n\ntype StyleElementMap = Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n>;\n\n// windowSheetsMap maps window objects to StyleElementMaps\n// A StyleElementMap maps css strings to style element tags\nconst windowSheetsMap = new WeakMap<Window, StyleElementMap>();\n\nexport function useComponentCssInjection({\n testId,\n css,\n window: targetWindow,\n}: UseComponentCssInjection): void {\n const styleInjectionEnabled = useStyleInjection();\n const insertionPoint = useInsertionPoint();\n\n maybeUseInsertionEffect(() => {\n if (!targetWindow || !styleInjectionEnabled) {\n return;\n }\n\n const sheetsMap =\n windowSheetsMap.get(targetWindow) ??\n new Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n >();\n const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };\n\n if (styleMap.styleElement == null) {\n styleMap.styleElement = targetWindow.document.createElement(\"style\");\n styleMap.styleElement.setAttribute(\"type\", \"text/css\");\n styleMap.styleElement.setAttribute(\"data-salt-style\", testId || \"\");\n styleMap.styleElement.textContent = css;\n\n styleMap.count = 1;\n\n targetWindow.document.head.insertBefore(\n styleMap.styleElement,\n insertionPoint || targetWindow.document.head.firstChild,\n );\n } else {\n styleMap.styleElement.textContent = css;\n styleMap.count++;\n }\n sheetsMap.set(css, styleMap);\n windowSheetsMap.set(targetWindow, sheetsMap);\n\n return () => {\n const sheetsMap = windowSheetsMap.get(targetWindow);\n const styleMap = sheetsMap?.get(css);\n if (styleMap?.styleElement) {\n styleMap.count--;\n if (styleMap.count < 1) {\n targetWindow.document.head.removeChild(styleMap.styleElement);\n styleMap.styleElement = null;\n sheetsMap?.delete(css);\n }\n }\n };\n }, [testId, css, targetWindow]);\n}\n"],"names":["React","useStyleInjection","useInsertionPoint","sheetsMap","styleMap"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAM,uBAAA;AAAA;AAAA,EAEHA,gBAAA,CAAc,oBAAA,CAAqB,QAAA,EAAU,KAAKA,gBAAA,CAAM;AAAA,CAAA;AAe3D,MAAM,eAAA,uBAAsB,OAAA,EAAiC;AAEtD,SAAS,wBAAA,CAAyB;AAAA,EACvC,MAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA,EAAQ;AACV,CAAA,EAAmC;AACjC,EAAA,MAAM,wBAAwBC,uBAAA,EAAkB;AAChD,EAAA,MAAM,iBAAiBC,wCAAA,EAAkB;AAEzC,EAAA,uBAAA,CAAwB,MAAM;AAC5B,IAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,qBAAA,EAAuB;AAC3C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,YACJ,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA,wBAC5B,GAAA,EAGF;AACJ,IAAA,MAAM,QAAA,GAAW,UAAU,GAAA,CAAI,GAAG,KAAK,EAAE,YAAA,EAAc,IAAA,EAAM,KAAA,EAAO,CAAA,EAAE;AAEtE,IAAA,IAAI,QAAA,CAAS,gBAAgB,IAAA,EAAM;AACjC,MAAA,QAAA,CAAS,YAAA,GAAe,YAAA,CAAa,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACnE,MAAA,QAAA,CAAS,YAAA,CAAa,YAAA,CAAa,MAAA,EAAQ,UAAU,CAAA;AACrD,MAAA,QAAA,CAAS,YAAA,CAAa,YAAA,CAAa,iBAAA,EAAmB,MAAA,IAAU,EAAE,CAAA;AAClE,MAAA,QAAA,CAAS,aAAa,WAAA,GAAc,GAAA;AAEpC,MAAA,QAAA,CAAS,KAAA,GAAQ,CAAA;AAEjB,MAAA,YAAA,CAAa,SAAS,IAAA,CAAK,YAAA;AAAA,QACzB,QAAA,CAAS,YAAA;AAAA,QACT,cAAA,IAAkB,YAAA,CAAa,QAAA,CAAS,IAAA,CAAK;AAAA,OAC/C;AAAA,IACF,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,aAAa,WAAA,GAAc,GAAA;AACpC,MAAA,QAAA,CAAS,KAAA,EAAA;AAAA,IACX;AACA,IAAA,SAAA,CAAU,GAAA,CAAI,KAAK,QAAQ,CAAA;AAC3B,IAAA,eAAA,CAAgB,GAAA,CAAI,cAAc,SAAS,CAAA;AAE3C,IAAA,OAAO,MAAM;AACX,MAAA,MAAMC,UAAAA,GAAY,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA;AAClD,MAAA,MAAMC,SAAAA,GAAWD,UAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,UAAAA,CAAW,GAAA,CAAI,GAAA,CAAA;AAChC,MAAA,IAAIC,SAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,SAAAA,CAAU,YAAA,EAAc;AAC1B,QAAAA,SAAAA,CAAS,KAAA,EAAA;AACT,QAAA,IAAIA,SAAAA,CAAS,QAAQ,CAAA,EAAG;AACtB,UAAA,YAAA,CAAa,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYA,SAAAA,CAAS,YAAY,CAAA;AAC5D,UAAAA,UAAS,YAAA,GAAe,IAAA;AACxB,UAAAD,UAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,UAAAA,CAAW,MAAA,CAAO,GAAA,CAAA;AAAA,QACpB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,GAAA,EAAK,YAAY,CAAC,CAAA;AAChC;;;;"}
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var clsx = require('clsx');
5
+ var React = require('react');
6
+
7
+ const EMPTY_REGISTRY = /* @__PURE__ */ new Map();
8
+ const InjectionContext = React.createContext(EMPTY_REGISTRY);
9
+ let hasWarnedExperimentalOnce = false;
10
+ function ClassNameInjectionProvider({
11
+ children,
12
+ value
13
+ }) {
14
+ const registry = React.useMemo(() => value ?? EMPTY_REGISTRY, [value]);
15
+ React.useEffect(() => {
16
+ if (!hasWarnedExperimentalOnce && process.env.NODE_ENV !== "production") {
17
+ console.warn(
18
+ "Salt ClassNameInjectionProvider is experimental and subject to change. JPM users: only recommended in non-production environments or with prior permission from the Salt team."
19
+ );
20
+ hasWarnedExperimentalOnce = true;
21
+ }
22
+ }, []);
23
+ return /* @__PURE__ */ jsxRuntime.jsx(InjectionContext.Provider, { value: registry, children });
24
+ }
25
+ function useClassNameInjection(component, props) {
26
+ const registry = React.useContext(InjectionContext);
27
+ const entries = registry.get(component) ?? [];
28
+ const deps = React.useMemo(
29
+ () => entries.length ? entries.flatMap((e) => e.keys.map((k) => props[k])) : [],
30
+ [entries, props]
31
+ );
32
+ const injected = React.useMemo(() => {
33
+ const { className: _ignore, ...restProps } = props;
34
+ if (!entries.length) return [];
35
+ return entries.map((e) => e.fn(restProps)).filter((v) => v != null);
36
+ }, [entries, deps, props]);
37
+ const className = React.useMemo(
38
+ () => clsx.clsx(props.className, injected) || void 0,
39
+ [props, injected]
40
+ );
41
+ const cleanProps = React.useMemo(() => {
42
+ const { className: _ignore, ...restProps } = props;
43
+ if (!entries.length) {
44
+ return restProps;
45
+ }
46
+ const copy = { ...restProps };
47
+ for (const entry of entries) {
48
+ for (const key of entry.keys) {
49
+ if (Object.hasOwn(copy, key)) {
50
+ delete copy[key];
51
+ }
52
+ }
53
+ }
54
+ return copy;
55
+ }, [entries, deps, props]);
56
+ return { className, props: cleanProps };
57
+ }
58
+ function registerClassInjector(registry, component, keys, injector) {
59
+ if (!registry.has(component)) {
60
+ registry.set(component, []);
61
+ }
62
+ const wrapped = (props) => {
63
+ const picked = Object.fromEntries(keys.map((k) => [k, props[k]]));
64
+ return injector(picked);
65
+ };
66
+ registry.get(component).push({
67
+ fn: wrapped,
68
+ keys
69
+ });
70
+ }
71
+
72
+ exports.ClassNameInjectionProvider = ClassNameInjectionProvider;
73
+ exports.registerClassInjector = registerClassInjector;
74
+ exports.useClassNameInjection = useClassNameInjection;
75
+ //# sourceMappingURL=useClassNameInjection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClassNameInjection.js","sources":["../src/useClassNameInjection.tsx"],"sourcesContent":["import { clsx } from \"clsx\";\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n} from \"react\";\n\n/**\n * Extensible map of supported components → their props.\n * @salt-ds/core must augment this with the components that support the API,\n * using the same key string that the component passes to useClassNameInjection,\n * e.g., \"saltButton\": ButtonProps.\n */\nexport interface ComponentPropsMap {}\n\ntype SupportedComponent = keyof ComponentPropsMap extends never\n ? \"ComponentPropsMap must be augmented to define the components that support useClassNameInjection\"\n : keyof ComponentPropsMap;\n\nexport type ClassNameInjector<Props, Keys extends keyof Props> = (\n props: Pick<Props, Keys>,\n) => string | undefined;\n\ninterface ClassNameInjectorEntry {\n fn: (props: unknown) => string | undefined;\n keys: string[];\n}\n\nexport type ClassNameInjectionRegistry<\n ComponentName extends SupportedComponent = SupportedComponent,\n> = Map<ComponentName, ClassNameInjectorEntry[]>;\n\nconst EMPTY_REGISTRY: ClassNameInjectionRegistry = new Map();\nconst InjectionContext =\n createContext<ClassNameInjectionRegistry>(EMPTY_REGISTRY);\n\nexport type ClassNameInjectionProviderProps = {\n children: ReactNode;\n value?: ClassNameInjectionRegistry;\n};\n\nlet hasWarnedExperimentalOnce = false;\n\nexport function ClassNameInjectionProvider({\n children,\n value,\n}: ClassNameInjectionProviderProps) {\n const registry = useMemo(() => value ?? EMPTY_REGISTRY, [value]);\n\n useEffect(() => {\n if (!hasWarnedExperimentalOnce && process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"Salt ClassNameInjectionProvider is experimental and subject to change. JPM users: only recommended in non-production environments or with prior permission from the Salt team.\",\n );\n hasWarnedExperimentalOnce = true;\n }\n }, []);\n\n return (\n <InjectionContext.Provider value={registry}>\n {children}\n </InjectionContext.Provider>\n );\n}\n\ntype PropsWithClassName = { className?: string } & Record<string, any>;\n\n/**\n * Return the className created by the registry and a props object with injector keys stripped.\n * Only components declared in ComponentPropsMap can call this at compile time.\n */\nexport function useClassNameInjection<Props extends PropsWithClassName>(\n component: SupportedComponent,\n props: Props,\n): { className: string | undefined; props: Omit<Props, \"className\"> } {\n const registry = useContext(InjectionContext);\n const entries = registry.get(component) ?? [];\n\n const deps = useMemo(\n () =>\n entries.length\n ? entries.flatMap((e) => e.keys.map((k) => (props as any)[k]))\n : [],\n [entries, props],\n );\n\n // Compute injected classes provided through ClassNameInjectionRegistry\n const injected = useMemo(() => {\n const { className: _ignore, ...restProps } = props as any;\n if (!entries.length) return [];\n return entries\n .map((e) => e.fn(restProps))\n .filter((v): v is string => v != null);\n }, [entries, deps, props]);\n\n // Merge original className with injected classes\n const className = useMemo(\n () => clsx((props as any).className, injected) || undefined,\n [props, injected],\n );\n\n // Create a cleaned props object by stripping keys used by injectors, to avoid DOM errors with unknown attributes\n const cleanProps = useMemo(() => {\n const { className: _ignore, ...restProps } = props as any;\n if (!entries.length) {\n return restProps as Omit<Props, \"className\">;\n }\n const copy = { ...restProps } as Omit<Props, \"className\">;\n for (const entry of entries) {\n for (const key of entry.keys) {\n if (Object.hasOwn(copy, key)) {\n delete (copy as any)[key];\n }\n }\n }\n return copy;\n }, [entries, deps, props]);\n\n return { className, props: cleanProps };\n}\n\n/**\n * Register a class injector for a supported component name.\n * - Keys must be valid string keys for that component’s props (as declared in ComponentPropsMap).\n * - Injector receives only the declared keys (Pick<PropsOf<C>, Keys>).\n */\nexport function registerClassInjector<\n Props extends Record<string, any>,\n Keys extends Extract<keyof Props, string>,\n>(\n registry: ClassNameInjectionRegistry,\n component: SupportedComponent,\n keys: Keys[],\n injector: ClassNameInjector<Props, Keys>,\n) {\n if (!registry.has(component)) {\n registry.set(component, []);\n }\n\n const wrapped = (props: Record<string, any>) => {\n const picked = Object.fromEntries(keys.map((k) => [k, props[k]])) as Pick<\n Props,\n Keys\n >;\n return injector(picked);\n };\n\n registry.get(component)!.push({\n fn: wrapped as (props: unknown) => string | undefined,\n keys: keys as string[],\n });\n}\n"],"names":["createContext","useMemo","useEffect","useContext","clsx"],"mappings":"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"}
package/dist-es/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { useComponentCssInjection } from './use-style-injection/useStyleInjection.js';
2
- export { InsertionPointProvider, useInsertionPoint } from './use-style-injection/InsertionPointProvider.js';
3
1
  export { StyleInjectionProvider, useStyleInjection } from './style-injection-provider/index.js';
2
+ export { InsertionPointProvider, useInsertionPoint } from './use-style-injection/InsertionPointProvider.js';
3
+ export { useComponentCssInjection } from './use-style-injection/useStyleInjection.js';
4
+ export { ClassNameInjectionProvider, registerClassInjector, useClassNameInjection } from './useClassNameInjection.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -4,15 +4,12 @@ import { createContext, useContext } from 'react';
4
4
  const StyleInjectionContext = createContext(true);
5
5
  function useStyleInjection(enableStyleInjection) {
6
6
  const enableStyleInjectionFromContext = useContext(StyleInjectionContext);
7
- return enableStyleInjection != null ? enableStyleInjection : enableStyleInjectionFromContext;
7
+ return enableStyleInjection ?? enableStyleInjectionFromContext;
8
8
  }
9
9
  function StyleInjectionProvider(props) {
10
10
  const { value: enableStyleInjectionProp, children } = props;
11
11
  const value = useStyleInjection(enableStyleInjectionProp);
12
- return /* @__PURE__ */ jsx(StyleInjectionContext.Provider, {
13
- value,
14
- children
15
- });
12
+ return /* @__PURE__ */ jsx(StyleInjectionContext.Provider, { value, children });
16
13
  }
17
14
 
18
15
  export { StyleInjectionProvider, useStyleInjection };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/style-injection-provider/index.tsx"],"sourcesContent":["import React, { type ReactNode, createContext, useContext } from \"react\";\nexport interface StyleInjectionContextType {\n value?: boolean;\n}\n\nconst StyleInjectionContext = createContext(true);\n\nexport function useStyleInjection(enableStyleInjection?: boolean): boolean {\n const enableStyleInjectionFromContext = useContext(StyleInjectionContext);\n return enableStyleInjection ?? enableStyleInjectionFromContext;\n}\n\nexport interface StyleInjectionProviderProps extends StyleInjectionContextType {\n children: ReactNode;\n}\n\nexport function StyleInjectionProvider(props: StyleInjectionProviderProps) {\n const { value: enableStyleInjectionProp, children } = props;\n const value = useStyleInjection(enableStyleInjectionProp);\n\n return (\n <StyleInjectionContext.Provider value={value}>\n {children}\n </StyleInjectionContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;AAKA,MAAM,qBAAA,GAAwB,cAAc,IAAI,CAAA,CAAA;AAEzC,SAAS,kBAAkB,oBAAyC,EAAA;AACzE,EAAM,MAAA,+BAAA,GAAkC,WAAW,qBAAqB,CAAA,CAAA;AACxE,EAAA,OAAO,oBAAwB,IAAA,IAAA,GAAA,oBAAA,GAAA,+BAAA,CAAA;AACjC,CAAA;AAMO,SAAS,uBAAuB,KAAoC,EAAA;AACzE,EAAA,MAAM,EAAE,KAAA,EAAO,wBAA0B,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AACtD,EAAM,MAAA,KAAA,GAAQ,kBAAkB,wBAAwB,CAAA,CAAA;AAExD,EACE,uBAAA,GAAA,CAAC,sBAAsB,QAAtB,EAAA;AAAA,IAA+B,KAAA;AAAA,IAC7B,QAAA;AAAA,GACH,CAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/style-injection-provider/index.tsx"],"sourcesContent":["import { createContext, type ReactNode, useContext } from \"react\";\nexport interface StyleInjectionContextType {\n value?: boolean;\n}\n\nconst StyleInjectionContext = createContext(true);\n\nexport function useStyleInjection(enableStyleInjection?: boolean): boolean {\n const enableStyleInjectionFromContext = useContext(StyleInjectionContext);\n return enableStyleInjection ?? enableStyleInjectionFromContext;\n}\n\nexport interface StyleInjectionProviderProps extends StyleInjectionContextType {\n children: ReactNode;\n}\n\nexport function StyleInjectionProvider(props: StyleInjectionProviderProps) {\n const { value: enableStyleInjectionProp, children } = props;\n const value = useStyleInjection(enableStyleInjectionProp);\n\n return (\n <StyleInjectionContext.Provider value={value}>\n {children}\n </StyleInjectionContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;AAKA,MAAM,qBAAA,GAAwB,cAAc,IAAI,CAAA;AAEzC,SAAS,kBAAkB,oBAAA,EAAyC;AACzE,EAAA,MAAM,+BAAA,GAAkC,WAAW,qBAAqB,CAAA;AACxE,EAAA,OAAO,oBAAA,IAAwB,+BAAA;AACjC;AAMO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,EAAE,KAAA,EAAO,wBAAA,EAA0B,QAAA,EAAS,GAAI,KAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,kBAAkB,wBAAwB,CAAA;AAExD,EAAA,uBACE,GAAA,CAAC,qBAAA,CAAsB,QAAA,EAAtB,EAA+B,OAC7B,QAAA,EACH,CAAA;AAEJ;;;;"}
@@ -8,10 +8,7 @@ if (process.env.NODE_ENV !== "production") {
8
8
  function InsertionPointProvider(props) {
9
9
  const { insertionPoint: insertionPointProp, children } = props;
10
10
  const value = useMemo(() => insertionPointProp, [insertionPointProp]);
11
- return /* @__PURE__ */ jsx(InsertionPointContext.Provider, {
12
- value,
13
- children
14
- });
11
+ return /* @__PURE__ */ jsx(InsertionPointContext.Provider, { value, children });
15
12
  }
16
13
  function useInsertionPoint() {
17
14
  const value = useContext(InsertionPointContext);
@@ -1 +1 @@
1
- {"version":3,"file":"InsertionPointProvider.js","sources":["../src/use-style-injection/InsertionPointProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext, useMemo } from \"react\";\n\nexport interface InsertionPointContextType {\n insertionPoint: ChildNode | null;\n}\n\nconst InsertionPointContext = createContext<ChildNode | null>(null);\n\nif (process.env.NODE_ENV !== \"production\") {\n InsertionPointContext.displayName = \"InsertionPointContext\";\n}\n\nexport interface InsertionPointProviderProps extends InsertionPointContextType {\n children: ReactNode;\n}\n\nexport function InsertionPointProvider(props: InsertionPointProviderProps) {\n const { insertionPoint: insertionPointProp, children } = props;\n const value = useMemo(() => insertionPointProp, [insertionPointProp]);\n\n return (\n <InsertionPointContext.Provider value={value}>\n {children}\n </InsertionPointContext.Provider>\n );\n}\n\nexport function useInsertionPoint() {\n const value = useContext(InsertionPointContext);\n return value;\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,qBAAA,GAAwB,cAAgC,IAAI,CAAA,CAAA;AAElE,IAAI,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AACzC,EAAA,qBAAA,CAAsB,WAAc,GAAA,uBAAA,CAAA;AACtC,CAAA;AAMO,SAAS,uBAAuB,KAAoC,EAAA;AACzE,EAAA,MAAM,EAAE,cAAA,EAAgB,kBAAoB,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AACzD,EAAA,MAAM,QAAQ,OAAQ,CAAA,MAAM,kBAAoB,EAAA,CAAC,kBAAkB,CAAC,CAAA,CAAA;AAEpE,EACE,uBAAA,GAAA,CAAC,sBAAsB,QAAtB,EAAA;AAAA,IAA+B,KAAA;AAAA,IAC7B,QAAA;AAAA,GACH,CAAA,CAAA;AAEJ,CAAA;AAEO,SAAS,iBAAoB,GAAA;AAClC,EAAM,MAAA,KAAA,GAAQ,WAAW,qBAAqB,CAAA,CAAA;AAC9C,EAAO,OAAA,KAAA,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"InsertionPointProvider.js","sources":["../src/use-style-injection/InsertionPointProvider.tsx"],"sourcesContent":["import { createContext, type ReactNode, useContext, useMemo } from \"react\";\n\nexport interface InsertionPointContextType {\n insertionPoint: ChildNode | null;\n}\n\nconst InsertionPointContext = createContext<ChildNode | null>(null);\n\nif (process.env.NODE_ENV !== \"production\") {\n InsertionPointContext.displayName = \"InsertionPointContext\";\n}\n\nexport interface InsertionPointProviderProps extends InsertionPointContextType {\n children: ReactNode;\n}\n\nexport function InsertionPointProvider(props: InsertionPointProviderProps) {\n const { insertionPoint: insertionPointProp, children } = props;\n const value = useMemo(() => insertionPointProp, [insertionPointProp]);\n\n return (\n <InsertionPointContext.Provider value={value}>\n {children}\n </InsertionPointContext.Provider>\n );\n}\n\nexport function useInsertionPoint() {\n const value = useContext(InsertionPointContext);\n return value;\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,qBAAA,GAAwB,cAAgC,IAAI,CAAA;AAElE,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,YAAA,EAAc;AACzC,EAAA,qBAAA,CAAsB,WAAA,GAAc,uBAAA;AACtC;AAMO,SAAS,uBAAuB,KAAA,EAAoC;AACzE,EAAA,MAAM,EAAE,cAAA,EAAgB,kBAAA,EAAoB,QAAA,EAAS,GAAI,KAAA;AACzD,EAAA,MAAM,QAAQ,OAAA,CAAQ,MAAM,kBAAA,EAAoB,CAAC,kBAAkB,CAAC,CAAA;AAEpE,EAAA,uBACE,GAAA,CAAC,qBAAA,CAAsB,QAAA,EAAtB,EAA+B,OAC7B,QAAA,EACH,CAAA;AAEJ;AAEO,SAAS,iBAAA,GAAoB;AAClC,EAAA,MAAM,KAAA,GAAQ,WAAW,qBAAqB,CAAA;AAC9C,EAAA,OAAO,KAAA;AACT;;;;"}
@@ -1,9 +1,11 @@
1
1
  import * as React from 'react';
2
- import { useInsertionPoint } from './InsertionPointProvider.js';
3
2
  import { useStyleInjection } from '../style-injection-provider/index.js';
3
+ import { useInsertionPoint } from './InsertionPointProvider.js';
4
4
 
5
- var _a;
6
- const maybeUseInsertionEffect = (_a = React["useInsertionEffect".toString()]) != null ? _a : React.useLayoutEffect;
5
+ const maybeUseInsertionEffect = (
6
+ // biome-ignore lint/suspicious/noExplicitAny: see comment above
7
+ React["useInsertionEffect".toString()] ?? React.useLayoutEffect
8
+ );
7
9
  const windowSheetsMap = /* @__PURE__ */ new WeakMap();
8
10
  function useComponentCssInjection({
9
11
  testId,
@@ -13,12 +15,11 @@ function useComponentCssInjection({
13
15
  const styleInjectionEnabled = useStyleInjection();
14
16
  const insertionPoint = useInsertionPoint();
15
17
  maybeUseInsertionEffect(() => {
16
- var _a2, _b;
17
18
  if (!targetWindow || !styleInjectionEnabled) {
18
19
  return;
19
20
  }
20
- const sheetsMap = (_a2 = windowSheetsMap.get(targetWindow)) != null ? _a2 : /* @__PURE__ */ new Map();
21
- const styleMap = (_b = sheetsMap.get(css)) != null ? _b : { styleElement: null, count: 0 };
21
+ const sheetsMap = windowSheetsMap.get(targetWindow) ?? /* @__PURE__ */ new Map();
22
+ const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };
22
23
  if (styleMap.styleElement == null) {
23
24
  styleMap.styleElement = targetWindow.document.createElement("style");
24
25
  styleMap.styleElement.setAttribute("type", "text/css");
@@ -1 +1 @@
1
- {"version":3,"file":"useStyleInjection.js","sources":["../src/use-style-injection/useStyleInjection.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useInsertionPoint } from \"./InsertionPointProvider\";\nimport { useStyleInjection } from \"../style-injection-provider\";\n\n/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any -- Workaround for https://github.com/webpack/webpack/issues/14814#issuecomment-1536757985 */\nconst maybeUseInsertionEffect: typeof React.useLayoutEffect =\n (React as any)[\"useInsertionEffect\".toString()] ?? React.useLayoutEffect;\n/* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */\n\nexport interface UseComponentCssInjection {\n testId?: string;\n css: string;\n window?: Window | null;\n}\n\ntype StyleElementMap = Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n>;\n\n// windowSheetsMap maps window objects to StyleElementMaps\n// A StyleElementMap maps css strings to style element tags\nconst windowSheetsMap = new WeakMap<Window, StyleElementMap>();\n\nexport function useComponentCssInjection({\n testId,\n css,\n window: targetWindow,\n}: UseComponentCssInjection): void {\n const styleInjectionEnabled = useStyleInjection();\n const insertionPoint = useInsertionPoint();\n\n maybeUseInsertionEffect(() => {\n if (!targetWindow || !styleInjectionEnabled) {\n return;\n }\n\n const sheetsMap =\n windowSheetsMap.get(targetWindow) ??\n new Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n >();\n const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };\n\n if (styleMap.styleElement == null) {\n styleMap.styleElement = targetWindow.document.createElement(\"style\");\n styleMap.styleElement.setAttribute(\"type\", \"text/css\");\n styleMap.styleElement.setAttribute(\"data-salt-style\", testId || \"\");\n styleMap.styleElement.textContent = css;\n\n styleMap.count = 1;\n\n targetWindow.document.head.insertBefore(\n styleMap.styleElement,\n insertionPoint || targetWindow.document.head.firstChild\n );\n } else {\n styleMap.styleElement.textContent = css;\n styleMap.count++;\n }\n sheetsMap.set(css, styleMap);\n windowSheetsMap.set(targetWindow, sheetsMap);\n\n return () => {\n const sheetsMap = windowSheetsMap.get(targetWindow);\n const styleMap = sheetsMap?.get(css);\n if (styleMap?.styleElement) {\n styleMap.count--;\n if (styleMap.count < 1) {\n targetWindow.document.head.removeChild(styleMap.styleElement);\n styleMap.styleElement = null;\n sheetsMap?.delete(css);\n }\n }\n };\n }, [testId, css, targetWindow]);\n}\n"],"names":["_a","sheetsMap","styleMap"],"mappings":"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"}
1
+ {"version":3,"file":"useStyleInjection.js","sources":["../src/use-style-injection/useStyleInjection.ts"],"sourcesContent":["import * as React from \"react\";\nimport { useStyleInjection } from \"../style-injection-provider\";\nimport { useInsertionPoint } from \"./InsertionPointProvider\";\n\n/* Workaround for https://github.com/webpack/webpack/issues/14814#issuecomment-1536757985 */\nconst maybeUseInsertionEffect: typeof React.useLayoutEffect =\n // biome-ignore lint/suspicious/noExplicitAny: see comment above\n (React as any)[\"useInsertionEffect\".toString()] ?? React.useLayoutEffect;\n\nexport interface UseComponentCssInjection {\n testId?: string;\n css: string;\n window?: Window | null;\n}\n\ntype StyleElementMap = Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n>;\n\n// windowSheetsMap maps window objects to StyleElementMaps\n// A StyleElementMap maps css strings to style element tags\nconst windowSheetsMap = new WeakMap<Window, StyleElementMap>();\n\nexport function useComponentCssInjection({\n testId,\n css,\n window: targetWindow,\n}: UseComponentCssInjection): void {\n const styleInjectionEnabled = useStyleInjection();\n const insertionPoint = useInsertionPoint();\n\n maybeUseInsertionEffect(() => {\n if (!targetWindow || !styleInjectionEnabled) {\n return;\n }\n\n const sheetsMap =\n windowSheetsMap.get(targetWindow) ??\n new Map<\n string,\n { styleElement: HTMLStyleElement | null; count: number }\n >();\n const styleMap = sheetsMap.get(css) ?? { styleElement: null, count: 0 };\n\n if (styleMap.styleElement == null) {\n styleMap.styleElement = targetWindow.document.createElement(\"style\");\n styleMap.styleElement.setAttribute(\"type\", \"text/css\");\n styleMap.styleElement.setAttribute(\"data-salt-style\", testId || \"\");\n styleMap.styleElement.textContent = css;\n\n styleMap.count = 1;\n\n targetWindow.document.head.insertBefore(\n styleMap.styleElement,\n insertionPoint || targetWindow.document.head.firstChild,\n );\n } else {\n styleMap.styleElement.textContent = css;\n styleMap.count++;\n }\n sheetsMap.set(css, styleMap);\n windowSheetsMap.set(targetWindow, sheetsMap);\n\n return () => {\n const sheetsMap = windowSheetsMap.get(targetWindow);\n const styleMap = sheetsMap?.get(css);\n if (styleMap?.styleElement) {\n styleMap.count--;\n if (styleMap.count < 1) {\n targetWindow.document.head.removeChild(styleMap.styleElement);\n styleMap.styleElement = null;\n sheetsMap?.delete(css);\n }\n }\n };\n }, [testId, css, targetWindow]);\n}\n"],"names":["sheetsMap","styleMap"],"mappings":";;;;AAKA,MAAM,uBAAA;AAAA;AAAA,EAEH,KAAA,CAAc,oBAAA,CAAqB,QAAA,EAAU,KAAK,KAAA,CAAM;AAAA,CAAA;AAe3D,MAAM,eAAA,uBAAsB,OAAA,EAAiC;AAEtD,SAAS,wBAAA,CAAyB;AAAA,EACvC,MAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA,EAAQ;AACV,CAAA,EAAmC;AACjC,EAAA,MAAM,wBAAwB,iBAAA,EAAkB;AAChD,EAAA,MAAM,iBAAiB,iBAAA,EAAkB;AAEzC,EAAA,uBAAA,CAAwB,MAAM;AAC5B,IAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,qBAAA,EAAuB;AAC3C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,YACJ,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA,wBAC5B,GAAA,EAGF;AACJ,IAAA,MAAM,QAAA,GAAW,UAAU,GAAA,CAAI,GAAG,KAAK,EAAE,YAAA,EAAc,IAAA,EAAM,KAAA,EAAO,CAAA,EAAE;AAEtE,IAAA,IAAI,QAAA,CAAS,gBAAgB,IAAA,EAAM;AACjC,MAAA,QAAA,CAAS,YAAA,GAAe,YAAA,CAAa,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACnE,MAAA,QAAA,CAAS,YAAA,CAAa,YAAA,CAAa,MAAA,EAAQ,UAAU,CAAA;AACrD,MAAA,QAAA,CAAS,YAAA,CAAa,YAAA,CAAa,iBAAA,EAAmB,MAAA,IAAU,EAAE,CAAA;AAClE,MAAA,QAAA,CAAS,aAAa,WAAA,GAAc,GAAA;AAEpC,MAAA,QAAA,CAAS,KAAA,GAAQ,CAAA;AAEjB,MAAA,YAAA,CAAa,SAAS,IAAA,CAAK,YAAA;AAAA,QACzB,QAAA,CAAS,YAAA;AAAA,QACT,cAAA,IAAkB,YAAA,CAAa,QAAA,CAAS,IAAA,CAAK;AAAA,OAC/C;AAAA,IACF,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,aAAa,WAAA,GAAc,GAAA;AACpC,MAAA,QAAA,CAAS,KAAA,EAAA;AAAA,IACX;AACA,IAAA,SAAA,CAAU,GAAA,CAAI,KAAK,QAAQ,CAAA;AAC3B,IAAA,eAAA,CAAgB,GAAA,CAAI,cAAc,SAAS,CAAA;AAE3C,IAAA,OAAO,MAAM;AACX,MAAA,MAAMA,UAAAA,GAAY,eAAA,CAAgB,GAAA,CAAI,YAAY,CAAA;AAClD,MAAA,MAAMC,SAAAA,GAAWD,UAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,UAAAA,CAAW,GAAA,CAAI,GAAA,CAAA;AAChC,MAAA,IAAIC,SAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,SAAAA,CAAU,YAAA,EAAc;AAC1B,QAAAA,SAAAA,CAAS,KAAA,EAAA;AACT,QAAA,IAAIA,SAAAA,CAAS,QAAQ,CAAA,EAAG;AACtB,UAAA,YAAA,CAAa,QAAA,CAAS,IAAA,CAAK,WAAA,CAAYA,SAAAA,CAAS,YAAY,CAAA;AAC5D,UAAAA,UAAS,YAAA,GAAe,IAAA;AACxB,UAAAD,UAAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,UAAAA,CAAW,MAAA,CAAO,GAAA,CAAA;AAAA,QACpB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,GAAA,EAAK,YAAY,CAAC,CAAA;AAChC;;;;"}
@@ -0,0 +1,71 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { clsx } from 'clsx';
3
+ import { createContext, useMemo, useEffect, useContext } from 'react';
4
+
5
+ const EMPTY_REGISTRY = /* @__PURE__ */ new Map();
6
+ const InjectionContext = createContext(EMPTY_REGISTRY);
7
+ let hasWarnedExperimentalOnce = false;
8
+ function ClassNameInjectionProvider({
9
+ children,
10
+ value
11
+ }) {
12
+ const registry = useMemo(() => value ?? EMPTY_REGISTRY, [value]);
13
+ useEffect(() => {
14
+ if (!hasWarnedExperimentalOnce && process.env.NODE_ENV !== "production") {
15
+ console.warn(
16
+ "Salt ClassNameInjectionProvider is experimental and subject to change. JPM users: only recommended in non-production environments or with prior permission from the Salt team."
17
+ );
18
+ hasWarnedExperimentalOnce = true;
19
+ }
20
+ }, []);
21
+ return /* @__PURE__ */ jsx(InjectionContext.Provider, { value: registry, children });
22
+ }
23
+ function useClassNameInjection(component, props) {
24
+ const registry = useContext(InjectionContext);
25
+ const entries = registry.get(component) ?? [];
26
+ const deps = useMemo(
27
+ () => entries.length ? entries.flatMap((e) => e.keys.map((k) => props[k])) : [],
28
+ [entries, props]
29
+ );
30
+ const injected = useMemo(() => {
31
+ const { className: _ignore, ...restProps } = props;
32
+ if (!entries.length) return [];
33
+ return entries.map((e) => e.fn(restProps)).filter((v) => v != null);
34
+ }, [entries, deps, props]);
35
+ const className = useMemo(
36
+ () => clsx(props.className, injected) || void 0,
37
+ [props, injected]
38
+ );
39
+ const cleanProps = useMemo(() => {
40
+ const { className: _ignore, ...restProps } = props;
41
+ if (!entries.length) {
42
+ return restProps;
43
+ }
44
+ const copy = { ...restProps };
45
+ for (const entry of entries) {
46
+ for (const key of entry.keys) {
47
+ if (Object.hasOwn(copy, key)) {
48
+ delete copy[key];
49
+ }
50
+ }
51
+ }
52
+ return copy;
53
+ }, [entries, deps, props]);
54
+ return { className, props: cleanProps };
55
+ }
56
+ function registerClassInjector(registry, component, keys, injector) {
57
+ if (!registry.has(component)) {
58
+ registry.set(component, []);
59
+ }
60
+ const wrapped = (props) => {
61
+ const picked = Object.fromEntries(keys.map((k) => [k, props[k]]));
62
+ return injector(picked);
63
+ };
64
+ registry.get(component).push({
65
+ fn: wrapped,
66
+ keys
67
+ });
68
+ }
69
+
70
+ export { ClassNameInjectionProvider, registerClassInjector, useClassNameInjection };
71
+ //# sourceMappingURL=useClassNameInjection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClassNameInjection.js","sources":["../src/useClassNameInjection.tsx"],"sourcesContent":["import { clsx } from \"clsx\";\nimport {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n} from \"react\";\n\n/**\n * Extensible map of supported components → their props.\n * @salt-ds/core must augment this with the components that support the API,\n * using the same key string that the component passes to useClassNameInjection,\n * e.g., \"saltButton\": ButtonProps.\n */\nexport interface ComponentPropsMap {}\n\ntype SupportedComponent = keyof ComponentPropsMap extends never\n ? \"ComponentPropsMap must be augmented to define the components that support useClassNameInjection\"\n : keyof ComponentPropsMap;\n\nexport type ClassNameInjector<Props, Keys extends keyof Props> = (\n props: Pick<Props, Keys>,\n) => string | undefined;\n\ninterface ClassNameInjectorEntry {\n fn: (props: unknown) => string | undefined;\n keys: string[];\n}\n\nexport type ClassNameInjectionRegistry<\n ComponentName extends SupportedComponent = SupportedComponent,\n> = Map<ComponentName, ClassNameInjectorEntry[]>;\n\nconst EMPTY_REGISTRY: ClassNameInjectionRegistry = new Map();\nconst InjectionContext =\n createContext<ClassNameInjectionRegistry>(EMPTY_REGISTRY);\n\nexport type ClassNameInjectionProviderProps = {\n children: ReactNode;\n value?: ClassNameInjectionRegistry;\n};\n\nlet hasWarnedExperimentalOnce = false;\n\nexport function ClassNameInjectionProvider({\n children,\n value,\n}: ClassNameInjectionProviderProps) {\n const registry = useMemo(() => value ?? EMPTY_REGISTRY, [value]);\n\n useEffect(() => {\n if (!hasWarnedExperimentalOnce && process.env.NODE_ENV !== \"production\") {\n console.warn(\n \"Salt ClassNameInjectionProvider is experimental and subject to change. JPM users: only recommended in non-production environments or with prior permission from the Salt team.\",\n );\n hasWarnedExperimentalOnce = true;\n }\n }, []);\n\n return (\n <InjectionContext.Provider value={registry}>\n {children}\n </InjectionContext.Provider>\n );\n}\n\ntype PropsWithClassName = { className?: string } & Record<string, any>;\n\n/**\n * Return the className created by the registry and a props object with injector keys stripped.\n * Only components declared in ComponentPropsMap can call this at compile time.\n */\nexport function useClassNameInjection<Props extends PropsWithClassName>(\n component: SupportedComponent,\n props: Props,\n): { className: string | undefined; props: Omit<Props, \"className\"> } {\n const registry = useContext(InjectionContext);\n const entries = registry.get(component) ?? [];\n\n const deps = useMemo(\n () =>\n entries.length\n ? entries.flatMap((e) => e.keys.map((k) => (props as any)[k]))\n : [],\n [entries, props],\n );\n\n // Compute injected classes provided through ClassNameInjectionRegistry\n const injected = useMemo(() => {\n const { className: _ignore, ...restProps } = props as any;\n if (!entries.length) return [];\n return entries\n .map((e) => e.fn(restProps))\n .filter((v): v is string => v != null);\n }, [entries, deps, props]);\n\n // Merge original className with injected classes\n const className = useMemo(\n () => clsx((props as any).className, injected) || undefined,\n [props, injected],\n );\n\n // Create a cleaned props object by stripping keys used by injectors, to avoid DOM errors with unknown attributes\n const cleanProps = useMemo(() => {\n const { className: _ignore, ...restProps } = props as any;\n if (!entries.length) {\n return restProps as Omit<Props, \"className\">;\n }\n const copy = { ...restProps } as Omit<Props, \"className\">;\n for (const entry of entries) {\n for (const key of entry.keys) {\n if (Object.hasOwn(copy, key)) {\n delete (copy as any)[key];\n }\n }\n }\n return copy;\n }, [entries, deps, props]);\n\n return { className, props: cleanProps };\n}\n\n/**\n * Register a class injector for a supported component name.\n * - Keys must be valid string keys for that component’s props (as declared in ComponentPropsMap).\n * - Injector receives only the declared keys (Pick<PropsOf<C>, Keys>).\n */\nexport function registerClassInjector<\n Props extends Record<string, any>,\n Keys extends Extract<keyof Props, string>,\n>(\n registry: ClassNameInjectionRegistry,\n component: SupportedComponent,\n keys: Keys[],\n injector: ClassNameInjector<Props, Keys>,\n) {\n if (!registry.has(component)) {\n registry.set(component, []);\n }\n\n const wrapped = (props: Record<string, any>) => {\n const picked = Object.fromEntries(keys.map((k) => [k, props[k]])) as Pick<\n Props,\n Keys\n >;\n return injector(picked);\n };\n\n registry.get(component)!.push({\n fn: wrapped as (props: unknown) => string | undefined,\n keys: keys as string[],\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
- export * from "./use-style-injection";
2
1
  export * from "./style-injection-provider";
2
+ export * from "./use-style-injection";
3
+ export * from "./useClassNameInjection";
@@ -6,4 +6,4 @@ export declare function useStyleInjection(enableStyleInjection?: boolean): boole
6
6
  export interface StyleInjectionProviderProps extends StyleInjectionContextType {
7
7
  children: ReactNode;
8
8
  }
9
- export declare function StyleInjectionProvider(props: StyleInjectionProviderProps): JSX.Element;
9
+ export declare function StyleInjectionProvider(props: StyleInjectionProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,9 @@
1
- import { ReactNode } from "react";
1
+ import { type ReactNode } from "react";
2
2
  export interface InsertionPointContextType {
3
3
  insertionPoint: ChildNode | null;
4
4
  }
5
5
  export interface InsertionPointProviderProps extends InsertionPointContextType {
6
6
  children: ReactNode;
7
7
  }
8
- export declare function InsertionPointProvider(props: InsertionPointProviderProps): JSX.Element;
8
+ export declare function InsertionPointProvider(props: InsertionPointProviderProps): import("react/jsx-runtime").JSX.Element;
9
9
  export declare function useInsertionPoint(): ChildNode | null;
@@ -1,2 +1,2 @@
1
- export * from "./useStyleInjection";
2
1
  export * from "./InsertionPointProvider";
2
+ export * from "./useStyleInjection";
@@ -0,0 +1,39 @@
1
+ import { type ReactNode } from "react";
2
+ /**
3
+ * Extensible map of supported components → their props.
4
+ * @salt-ds/core must augment this with the components that support the API,
5
+ * using the same key string that the component passes to useClassNameInjection,
6
+ * e.g., "saltButton": ButtonProps.
7
+ */
8
+ export interface ComponentPropsMap {
9
+ }
10
+ type SupportedComponent = keyof ComponentPropsMap extends never ? "ComponentPropsMap must be augmented to define the components that support useClassNameInjection" : keyof ComponentPropsMap;
11
+ export type ClassNameInjector<Props, Keys extends keyof Props> = (props: Pick<Props, Keys>) => string | undefined;
12
+ interface ClassNameInjectorEntry {
13
+ fn: (props: unknown) => string | undefined;
14
+ keys: string[];
15
+ }
16
+ export type ClassNameInjectionRegistry<ComponentName extends SupportedComponent = SupportedComponent> = Map<ComponentName, ClassNameInjectorEntry[]>;
17
+ export type ClassNameInjectionProviderProps = {
18
+ children: ReactNode;
19
+ value?: ClassNameInjectionRegistry;
20
+ };
21
+ export declare function ClassNameInjectionProvider({ children, value, }: ClassNameInjectionProviderProps): import("react/jsx-runtime").JSX.Element;
22
+ type PropsWithClassName = {
23
+ className?: string;
24
+ } & Record<string, any>;
25
+ /**
26
+ * Return the className created by the registry and a props object with injector keys stripped.
27
+ * Only components declared in ComponentPropsMap can call this at compile time.
28
+ */
29
+ export declare function useClassNameInjection<Props extends PropsWithClassName>(component: SupportedComponent, props: Props): {
30
+ className: string | undefined;
31
+ props: Omit<Props, "className">;
32
+ };
33
+ /**
34
+ * Register a class injector for a supported component name.
35
+ * - Keys must be valid string keys for that component’s props (as declared in ComponentPropsMap).
36
+ * - Injector receives only the declared keys (Pick<PropsOf<C>, Keys>).
37
+ */
38
+ export declare function registerClassInjector<Props extends Record<string, any>, Keys extends Extract<keyof Props, string>>(registry: ClassNameInjectionRegistry, component: SupportedComponent, keys: Keys[], injector: ClassNameInjector<Props, Keys>): void;
39
+ export {};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@salt-ds/styles",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/jpmorganchase/salt-ds.git",
7
+ "url": "git+https://github.com/jpmorganchase/salt-ds.git",
8
8
  "directory": "packages/styles"
9
9
  },
10
10
  "bugs": "https://github.com/jpmorganchase/salt-ds/issues",
@@ -24,13 +24,16 @@
24
24
  "directory": "../../dist/salt-ds-styles",
25
25
  "provenance": true
26
26
  },
27
+ "scripts": {
28
+ "build": "yarn node ../../scripts/build.mjs"
29
+ },
30
+ "dependencies": {},
27
31
  "module": "dist-es/index.js",
28
32
  "typings": "dist-types/index.d.ts",
29
- "dependencies": {},
30
33
  "files": [
31
34
  "dist-cjs",
32
35
  "dist-es",
33
36
  "dist-types",
34
- "README.md"
37
+ "CHANGELOG.md"
35
38
  ]
36
39
  }