jfs-components 0.0.64 → 0.0.66

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 (46) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/commonjs/components/CardCTA/CardCTA.js +15 -1
  3. package/lib/commonjs/components/Carousel/Carousel.js +34 -13
  4. package/lib/commonjs/components/Drawer/Drawer.js +9 -3
  5. package/lib/commonjs/components/IconButton/IconButton.js +42 -6
  6. package/lib/commonjs/components/IconCapsule/IconCapsule.js +5 -0
  7. package/lib/commonjs/components/Popup/Popup.js +2 -2
  8. package/lib/commonjs/components/Section/Section.js +22 -7
  9. package/lib/commonjs/components/UpiHandle/UpiHandle.js +19 -7
  10. package/lib/commonjs/icons/Icon.js +72 -75
  11. package/lib/commonjs/icons/registry.js +1 -1
  12. package/lib/commonjs/utils/MediaSource.js +181 -0
  13. package/lib/commonjs/utils/index.js +9 -1
  14. package/lib/module/components/CardCTA/CardCTA.js +15 -1
  15. package/lib/module/components/Carousel/Carousel.js +34 -13
  16. package/lib/module/components/Drawer/Drawer.js +9 -3
  17. package/lib/module/components/IconButton/IconButton.js +42 -6
  18. package/lib/module/components/IconCapsule/IconCapsule.js +5 -0
  19. package/lib/module/components/Popup/Popup.js +2 -2
  20. package/lib/module/components/Section/Section.js +23 -8
  21. package/lib/module/components/UpiHandle/UpiHandle.js +20 -8
  22. package/lib/module/icons/Icon.js +72 -75
  23. package/lib/module/icons/registry.js +1 -1
  24. package/lib/module/utils/MediaSource.js +176 -0
  25. package/lib/module/utils/index.js +2 -1
  26. package/lib/typescript/src/components/Drawer/Drawer.d.ts +6 -1
  27. package/lib/typescript/src/components/IconButton/IconButton.d.ts +25 -14
  28. package/lib/typescript/src/components/IconCapsule/IconCapsule.d.ts +12 -1
  29. package/lib/typescript/src/components/UpiHandle/UpiHandle.d.ts +17 -3
  30. package/lib/typescript/src/icons/Icon.d.ts +35 -16
  31. package/lib/typescript/src/icons/registry.d.ts +1 -1
  32. package/lib/typescript/src/utils/MediaSource.d.ts +63 -0
  33. package/lib/typescript/src/utils/index.d.ts +2 -0
  34. package/package.json +1 -1
  35. package/src/components/CardCTA/CardCTA.tsx +13 -0
  36. package/src/components/Carousel/Carousel.tsx +37 -20
  37. package/src/components/Drawer/Drawer.tsx +13 -2
  38. package/src/components/IconButton/IconButton.tsx +70 -11
  39. package/src/components/IconCapsule/IconCapsule.tsx +13 -0
  40. package/src/components/Popup/Popup.tsx +2 -2
  41. package/src/components/Section/Section.tsx +29 -12
  42. package/src/components/UpiHandle/UpiHandle.tsx +37 -11
  43. package/src/icons/Icon.tsx +91 -76
  44. package/src/icons/registry.ts +1 -1
  45. package/src/utils/MediaSource.tsx +220 -0
  46. package/src/utils/index.ts +2 -0
@@ -0,0 +1,220 @@
1
+ import React from 'react'
2
+ import {
3
+ Image,
4
+ type ImageStyle,
5
+ type ImageURISource,
6
+ type StyleProp,
7
+ } from 'react-native'
8
+ import { SvgUri, SvgXml } from 'react-native-svg'
9
+
10
+ /**
11
+ * A unified, "do-the-right-thing" image source accepted by `MediaSource` and
12
+ * by the `source` prop on `Icon`, `IconCapsule` and `UpiHandle`.
13
+ *
14
+ * Accepts any of:
15
+ * - `string` — a URI (raster or `.svg`) **or** an inline SVG XML document
16
+ * (`'<svg …>…</svg>'`).
17
+ * - `number` — a Metro asset id from `require('./foo.png')`.
18
+ * - `{ uri, … }` — the standard RN `ImageURISource` object (works for both
19
+ * raster and `.svg` URIs).
20
+ * - `React.ComponentType` — an SVG React component (e.g. produced by
21
+ * `react-native-svg-transformer`, by `@svgr/*`,
22
+ * or hand-written). It is rendered with
23
+ * `{ width, height, color, fill }` so it can be
24
+ * tinted just like a built-in icon.
25
+ * - `React.ReactElement` — an already-rendered node, passed through verbatim.
26
+ *
27
+ * The helper sniffs the input shape (no extension hint required from the
28
+ * caller) and picks the correct renderer for the platform.
29
+ */
30
+ export type UnifiedSource =
31
+ | string
32
+ | number
33
+ | ImageURISource
34
+ | React.ComponentType<{
35
+ width?: number
36
+ height?: number
37
+ color?: string
38
+ fill?: string
39
+ }>
40
+ | React.ReactElement
41
+
42
+ export type MediaSourceProps = {
43
+ /** Smart source. See {@link UnifiedSource}. */
44
+ source: UnifiedSource
45
+ /** Convenience shorthand that sets both width and height. */
46
+ size?: number
47
+ width?: number
48
+ height?: number
49
+ /**
50
+ * Optional tint applied to the rendered media.
51
+ * - Raster `<Image>` → mapped to `style.tintColor` (works on iOS, Android,
52
+ * and react-native-web).
53
+ * - SVG (XML / URI / component) → mapped to the `color` / `fill` props.
54
+ * For an SVG to actually re-color, its source must use `currentColor`
55
+ * (or have no hardcoded fill). SVGs with baked-in `fill="#xxx"` cannot
56
+ * be re-tinted without parsing — this is a `react-native-svg`
57
+ * limitation, not something we can paper over here.
58
+ */
59
+ tintColor?: string
60
+ /** Extra style merged into the underlying `<Image>` (raster path only). */
61
+ style?: StyleProp<ImageStyle>
62
+ resizeMode?: 'cover' | 'contain' | 'stretch' | 'center' | 'repeat'
63
+ accessibilityElementsHidden?: boolean
64
+ importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants'
65
+ }
66
+
67
+ const SVG_XML_RE = /<svg[\s>]/i
68
+ const SVG_URI_RE = /\.svg(\?|#|$)/i
69
+
70
+ function isSvgXml(s: string): boolean {
71
+ return /^\s*</.test(s) && SVG_XML_RE.test(s)
72
+ }
73
+
74
+ function isSvgUri(s: string): boolean {
75
+ return SVG_URI_RE.test(s)
76
+ }
77
+
78
+ function isUriObject(
79
+ v: unknown
80
+ ): v is ImageURISource & { uri: string } {
81
+ return (
82
+ typeof v === 'object' &&
83
+ v !== null &&
84
+ 'uri' in v &&
85
+ typeof (v as { uri: unknown }).uri === 'string'
86
+ )
87
+ }
88
+
89
+ /**
90
+ * Smart renderer that picks the right primitive for the source shape. See
91
+ * {@link UnifiedSource}.
92
+ *
93
+ * Designed to be used internally by `Icon`, `IconCapsule`, and `UpiHandle`,
94
+ * but also exported for ad-hoc consumer use.
95
+ */
96
+ function MediaSource(props: MediaSourceProps) {
97
+ const {
98
+ source,
99
+ size,
100
+ width,
101
+ height,
102
+ tintColor,
103
+ style,
104
+ resizeMode = 'cover',
105
+ accessibilityElementsHidden,
106
+ importantForAccessibility,
107
+ } = props
108
+
109
+ const w = width ?? size
110
+ const h = height ?? size
111
+
112
+ // Pre-rendered element — pass through.
113
+ if (React.isValidElement(source)) {
114
+ return source
115
+ }
116
+
117
+ // SVG / icon component.
118
+ if (typeof source === 'function') {
119
+ const Comp = source as React.ComponentType<{
120
+ width?: number
121
+ height?: number
122
+ color?: string
123
+ fill?: string
124
+ }>
125
+ return (
126
+ <Comp
127
+ {...(w !== undefined ? { width: w } : {})}
128
+ {...(h !== undefined ? { height: h } : {})}
129
+ {...(tintColor !== undefined ? { color: tintColor, fill: tintColor } : {})}
130
+ />
131
+ )
132
+ }
133
+
134
+ const sizeStyle: ImageStyle | null =
135
+ w !== undefined || h !== undefined ? { width: w, height: h } : null
136
+ const tintStyle: ImageStyle | null = tintColor ? { tintColor } : null
137
+ const composedStyle: StyleProp<ImageStyle> = [sizeStyle, tintStyle, style]
138
+
139
+ if (typeof source === 'string') {
140
+ if (isSvgXml(source)) {
141
+ return (
142
+ <SvgXml
143
+ xml={source}
144
+ {...(w !== undefined ? { width: w } : {})}
145
+ {...(h !== undefined ? { height: h } : {})}
146
+ {...(tintColor !== undefined ? { color: tintColor } : {})}
147
+ />
148
+ )
149
+ }
150
+ if (isSvgUri(source)) {
151
+ return (
152
+ <SvgUri
153
+ uri={source}
154
+ {...(w !== undefined ? { width: w } : {})}
155
+ {...(h !== undefined ? { height: h } : {})}
156
+ {...(tintColor !== undefined ? { color: tintColor } : {})}
157
+ />
158
+ )
159
+ }
160
+ return (
161
+ <Image
162
+ source={{ uri: source }}
163
+ style={composedStyle}
164
+ resizeMode={resizeMode}
165
+ {...(accessibilityElementsHidden !== undefined
166
+ ? { accessibilityElementsHidden }
167
+ : {})}
168
+ {...(importantForAccessibility !== undefined
169
+ ? { importantForAccessibility }
170
+ : {})}
171
+ />
172
+ )
173
+ }
174
+
175
+ if (isUriObject(source)) {
176
+ if (isSvgUri(source.uri)) {
177
+ return (
178
+ <SvgUri
179
+ uri={source.uri}
180
+ {...(w !== undefined ? { width: w } : {})}
181
+ {...(h !== undefined ? { height: h } : {})}
182
+ {...(tintColor !== undefined ? { color: tintColor } : {})}
183
+ />
184
+ )
185
+ }
186
+ return (
187
+ <Image
188
+ source={source}
189
+ style={composedStyle}
190
+ resizeMode={resizeMode}
191
+ {...(accessibilityElementsHidden !== undefined
192
+ ? { accessibilityElementsHidden }
193
+ : {})}
194
+ {...(importantForAccessibility !== undefined
195
+ ? { importantForAccessibility }
196
+ : {})}
197
+ />
198
+ )
199
+ }
200
+
201
+ if (typeof source === 'number') {
202
+ return (
203
+ <Image
204
+ source={source}
205
+ style={composedStyle}
206
+ resizeMode={resizeMode}
207
+ {...(accessibilityElementsHidden !== undefined
208
+ ? { accessibilityElementsHidden }
209
+ : {})}
210
+ {...(importantForAccessibility !== undefined
211
+ ? { importantForAccessibility }
212
+ : {})}
213
+ />
214
+ )
215
+ }
216
+
217
+ return null
218
+ }
219
+
220
+ export default React.memo(MediaSource)
@@ -1 +1,3 @@
1
1
  export { cloneChildrenWithModes, flattenChildren } from './react-utils'
2
+ export { default as MediaSource } from './MediaSource'
3
+ export type { UnifiedSource, MediaSourceProps } from './MediaSource'