@bwp-web/components 1.1.0 → 1.1.2

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/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @bwp-web/components
10
10
 
11
11
  ### Peer Dependencies
12
12
 
13
- - `@bwp-web/styles` >= 1.0.3
13
+ - `@bwp-web/styles` >= 1.0.4
14
14
  - `@bwp-web/assets` >= 1.0.2
15
15
  - `@mui/material` >= 7.0.0
16
16
  - `react` >= 18.0.0
@@ -266,16 +266,17 @@ import BrokenImageIcon from '@mui/icons-material/BrokenImage';
266
266
 
267
267
  #### DynamicSvgIcon Props
268
268
 
269
- | Prop | Type | Default | Description |
270
- | ------------------- | ------------------------------------------ | ------------ | ------------------------------------------------- |
271
- | `url` | `string` | — | URL of the SVG to fetch |
272
- | `fallback` | `React.ReactNode` | **required** | Element shown when loading fails |
273
- | `width` | `number` | `24` | Width in pixels for icon, skeleton, and fallback |
274
- | `height` | `number` | `24` | Height in pixels for icon, skeleton, and fallback |
275
- | `skeletonVariant` | `'circular' \| 'rectangular' \| 'rounded'` | `'circular'` | Skeleton shape during loading |
276
- | `skeletonAnimation` | `'pulse' \| 'wave' \| false` | `'pulse'` | Skeleton animation type |
277
- | `onLoad` | `() => void` | | Called when the SVG loads successfully |
278
- | `onError` | `(error: string) => void` | — | Called when loading fails |
269
+ | Prop | Type | Default | Description |
270
+ | ------------------- | ------------------------------------------ | ------------ | -------------------------------------------------------------- |
271
+ | `url` | `string` | — | URL of the SVG to fetch |
272
+ | `fallback` | `React.ReactNode` | **required** | Element shown when loading fails |
273
+ | `width` | `number` | `24` | Width in pixels for icon, skeleton, and fallback |
274
+ | `height` | `number` | `24` | Height in pixels for icon, skeleton, and fallback |
275
+ | `replaceColors` | `boolean` | `false` | Replace all fill/stroke colors with `currentColor` for theming |
276
+ | `skeletonVariant` | `'circular' \| 'rectangular' \| 'rounded'` | `'circular'` | Skeleton shape during loading |
277
+ | `skeletonAnimation` | `'pulse' \| 'wave' \| false` | `'pulse'` | Skeleton animation type |
278
+ | `onLoad` | `() => void` | — | Called when the SVG loads successfully |
279
+ | `onError` | `(error: string) => void` | — | Called when loading fails |
279
280
 
280
281
  ### BiampTable
281
282
 
@@ -2,6 +2,14 @@ import type { SvgIconProps } from '@mui/material';
2
2
  /** Clear the internal SVG fetch cache. Useful for testing or forcing a refetch. */
3
3
  export declare function clearDynamicSvgIconCache(): void;
4
4
  export interface UseDynamicSvgIconOptions {
5
+ /**
6
+ * When `true`, all `fill` and `stroke` attribute values (except `"none"` and
7
+ * `"currentColor"`) are replaced with `"currentColor"`. This makes the SVG
8
+ * fully themeable via the CSS `color` property or MUI's `sx={{ color }}`.
9
+ *
10
+ * @default false
11
+ */
12
+ replaceColors?: boolean;
5
13
  /** Called when the SVG loads successfully */
6
14
  onLoad?: () => void;
7
15
  /** Called when loading fails */
@@ -19,7 +27,8 @@ export interface UseDynamicSvgIconResult {
19
27
  }
20
28
  /**
21
29
  * Hook that fetches an SVG from a URL and returns the parsed content.
22
- * The SVG is rendered as-is colors and viewBox are preserved from the source.
30
+ * The SVG is rendered as-is by default. Pass `replaceColors: true` to replace
31
+ * all fill/stroke colors with `currentColor` for full theming support.
23
32
  * Results are cached in-memory so subsequent renders with the same URL are instant.
24
33
  *
25
34
  * @param url - URL of the SVG to fetch (supports any URL that `fetch` can handle, including data URLs)
@@ -44,6 +53,14 @@ export interface DynamicSvgIconProps extends Omit<SvgIconProps, 'children' | 'on
44
53
  width?: number;
45
54
  /** Height in pixels — applied to icon, skeleton, and fallback (default: 24) */
46
55
  height?: number;
56
+ /**
57
+ * Replace all fill/stroke colors (except `"none"` and `"currentColor"`) with
58
+ * `"currentColor"`, making the icon fully themeable via CSS `color`.
59
+ * Set to `false` to preserve the SVG's original colors.
60
+ *
61
+ * @default false
62
+ */
63
+ replaceColors?: boolean;
47
64
  /** Skeleton shape shown during loading (default: 'circular') */
48
65
  skeletonVariant?: 'circular' | 'rectangular' | 'rounded';
49
66
  /** Skeleton animation type (default: 'pulse') */
@@ -60,7 +77,8 @@ export interface DynamicSvgIconProps extends Omit<SvgIconProps, 'children' | 'on
60
77
  *
61
78
  * The SVG is rendered as-is — fill, stroke, and viewBox are preserved from the
62
79
  * source. Paths without an explicit fill will inherit `currentColor` from MUI
63
- * SvgIcon's CSS, so they respond to the parent's text color.
80
+ * SvgIcon's CSS. Set `replaceColors` to force **all** fills and strokes to
81
+ * `"currentColor"`, making the icon fully themeable via CSS `color`.
64
82
  *
65
83
  * Fetched SVGs are cached in-memory; the same URL will only be fetched once
66
84
  * per page session. Use {@link clearDynamicSvgIconCache} to force a refetch.
@@ -76,5 +94,5 @@ export interface DynamicSvgIconProps extends Omit<SvgIconProps, 'children' | 'on
76
94
  * />
77
95
  * ```
78
96
  */
79
- export declare function DynamicSvgIcon({ url, fallback, width, height, skeletonVariant, skeletonAnimation, onLoad, onError, sx, ...svgIconProps }: DynamicSvgIconProps): import("react/jsx-runtime").JSX.Element;
97
+ export declare function DynamicSvgIcon({ url, fallback, width, height, replaceColors, skeletonVariant, skeletonAnimation, onLoad, onError, sx, ...svgIconProps }: DynamicSvgIconProps): import("react/jsx-runtime").JSX.Element;
80
98
  //# sourceMappingURL=DynamicSvgIcon.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DynamicSvgIcon.d.ts","sourceRoot":"","sources":["../../src/DynamicSvgIcon/DynamicSvgIcon.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAUlD,mFAAmF;AACnF,wBAAgB,wBAAwB,SAEvC;AAED,MAAM,WAAW,wBAAwB;IACvC,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kDAAkD;IAClD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,wBAA6B,GACrC,uBAAuB,CAwFzB;AAID,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAC/C,YAAY,EACZ,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CACvD;IACC,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,eAAe,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IACzD,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAC7C,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,QAAQ,EACR,KAAoB,EACpB,MAAqB,EACrB,eAA4B,EAC5B,iBAA2B,EAC3B,MAAM,EACN,OAAO,EACP,EAAE,EACF,GAAG,YAAY,EAChB,EAAE,mBAAmB,2CAqDrB"}
1
+ {"version":3,"file":"DynamicSvgIcon.d.ts","sourceRoot":"","sources":["../../src/DynamicSvgIcon/DynamicSvgIcon.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAUlD,mFAAmF;AACnF,wBAAgB,wBAAwB,SAEvC;AAYD,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kDAAkD;IAClD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,wBAA6B,GACrC,uBAAuB,CA0FzB;AAID,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAC/C,YAAY,EACZ,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CACvD;IACC,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gEAAgE;IAChE,eAAe,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IACzD,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAC7C,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gCAAgC;IAChC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,QAAQ,EACR,KAAoB,EACpB,MAAqB,EACrB,aAAa,EACb,eAA4B,EAC5B,iBAA2B,EAC3B,MAAM,EACN,OAAO,EACP,EAAE,EACF,GAAG,YAAY,EAChB,EAAE,mBAAmB,2CAsDrB"}
package/dist/index.cjs CHANGED
@@ -2771,11 +2771,15 @@ var svgCache = /* @__PURE__ */ new Map();
2771
2771
  function clearDynamicSvgIconCache() {
2772
2772
  svgCache.clear();
2773
2773
  }
2774
+ function applyCurrentColor(svg) {
2775
+ return svg.replace(/fill="(?!none|currentColor)[^"]*"/g, 'fill="currentColor"').replace(/stroke="(?!none|currentColor)[^"]*"/g, 'stroke="currentColor"');
2776
+ }
2774
2777
  function useDynamicSvgIcon(url, options = {}) {
2775
- const { onLoad, onError } = options;
2778
+ const { replaceColors = false, onLoad, onError } = options;
2779
+ const transform = replaceColors ? applyCurrentColor : (s) => s;
2776
2780
  const [svgContent, setSvgContent] = (0, import_react12.useState)(() => {
2777
2781
  const cached = svgCache.get(url);
2778
- return cached ? cached.innerContent : null;
2782
+ return cached ? transform(cached.innerContent) : null;
2779
2783
  });
2780
2784
  const [svgViewBox, setSvgViewBox] = (0, import_react12.useState)(() => {
2781
2785
  const cached = svgCache.get(url);
@@ -2794,7 +2798,7 @@ function useDynamicSvgIcon(url, options = {}) {
2794
2798
  let cancelled = false;
2795
2799
  const cached = svgCache.get(url);
2796
2800
  if (cached) {
2797
- setSvgContent(cached.innerContent);
2801
+ setSvgContent(transform(cached.innerContent));
2798
2802
  setSvgViewBox(cached.viewBox);
2799
2803
  setLoading(false);
2800
2804
  setError(null);
@@ -2824,7 +2828,7 @@ function useDynamicSvgIcon(url, options = {}) {
2824
2828
  const innerContent = svgMatch ? svgMatch[1] : text;
2825
2829
  svgCache.set(url, { innerContent, viewBox });
2826
2830
  if (!cancelled) {
2827
- setSvgContent(innerContent);
2831
+ setSvgContent(transform(innerContent));
2828
2832
  setSvgViewBox(viewBox);
2829
2833
  setLoading(false);
2830
2834
  onLoad?.();
@@ -2850,6 +2854,7 @@ function DynamicSvgIcon({
2850
2854
  fallback,
2851
2855
  width = DEFAULT_SIZE2,
2852
2856
  height = DEFAULT_SIZE2,
2857
+ replaceColors,
2853
2858
  skeletonVariant = "circular",
2854
2859
  skeletonAnimation = "pulse",
2855
2860
  onLoad,
@@ -2858,6 +2863,7 @@ function DynamicSvgIcon({
2858
2863
  ...svgIconProps
2859
2864
  }) {
2860
2865
  const { loading, error, svgContent, svgViewBox } = useDynamicSvgIcon(url, {
2866
+ replaceColors,
2861
2867
  onLoad,
2862
2868
  onError
2863
2869
  });