@honeypathkar/react-native-lq-bottom-bar 0.0.0-stage → 0.1.1

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 (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -2
  3. package/android/build.gradle +78 -0
  4. package/android/src/main/AndroidManifest.xml +1 -0
  5. package/android/src/main/java/com/honeypathkar/lqbottombar/BackdropBlur.kt +428 -0
  6. package/android/src/main/java/com/honeypathkar/lqbottombar/LQBottomBarPackage.kt +34 -0
  7. package/android/src/main/java/com/honeypathkar/lqbottombar/LQBottomBarView.kt +503 -0
  8. package/android/src/main/java/com/honeypathkar/lqbottombar/LQBottomBarViewManager.kt +119 -0
  9. package/android/src/main/java/com/honeypathkar/lqbottombar/TabSelectedEvent.kt +30 -0
  10. package/ios/LQBottomBarView.swift +328 -0
  11. package/ios/LQBottomBarViewManager.m +21 -0
  12. package/ios/LQBottomBarViewManager.swift +36 -0
  13. package/lib/commonjs/NativeBottomBar.d.ts +33 -0
  14. package/lib/commonjs/NativeBottomBar.d.ts.map +1 -0
  15. package/lib/commonjs/NativeBottomBar.js +9 -0
  16. package/lib/commonjs/NativeBottomBar.js.map +1 -0
  17. package/lib/commonjs/index.d.ts +6 -0
  18. package/lib/commonjs/index.d.ts.map +1 -0
  19. package/lib/commonjs/index.js +131 -0
  20. package/lib/commonjs/index.js.map +1 -0
  21. package/lib/commonjs/rasterise.d.ts +20 -0
  22. package/lib/commonjs/rasterise.d.ts.map +1 -0
  23. package/lib/commonjs/rasterise.js +398 -0
  24. package/lib/commonjs/rasterise.js.map +1 -0
  25. package/lib/commonjs/types.d.ts +119 -0
  26. package/lib/commonjs/types.d.ts.map +1 -0
  27. package/lib/commonjs/types.js +3 -0
  28. package/lib/commonjs/types.js.map +1 -0
  29. package/package.json +65 -4
  30. package/react-native-lq-bottom-bar.podspec +27 -0
  31. package/src/NativeBottomBar.ts +43 -0
  32. package/src/index.tsx +139 -0
  33. package/src/rasterise.tsx +444 -0
  34. package/src/types.ts +136 -0
@@ -0,0 +1,398 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.useRasterisedIcons = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ /**
40
+ * TURNING A REACT ICON INTO A UIImage.
41
+ *
42
+ * `UITabBar` renders its items natively and accepts only `UIImage`. That is
43
+ * not a limitation to argue with — it is the reason the bar looks and behaves
44
+ * like the system's own, since UIKit is drawing the items rather than
45
+ * compositing someone else's views over them.
46
+ *
47
+ * So the icon has to become an image BEFORE it reaches the bar. The way out
48
+ * is react-native-svg's `toDataURL()`: mount the icon off-screen once, ask the
49
+ * native SVG view to render itself into a PNG, hand the base64 to the bar,
50
+ * and remember the result. A lucide icon is a react-native-svg `<Svg>` with a
51
+ * forwarded ref, so one path covers lucide and hand-written SVG alike.
52
+ *
53
+ * THE ALTERNATIVE, for the record: overlay JS icons on top of the native bar.
54
+ * That accepts any renderer and needs none of this file — but it forfeits
55
+ * UIKit's selection animation, which is the thing the native bar is for. A
56
+ * one-off rasterisation is the cheaper trade.
57
+ *
58
+ * WHAT THIS COSTS. The first frame for an uncached icon has a title and no
59
+ * glyph. The cache is module-level, so it is one frame per distinct icon per
60
+ * app launch, not per mount — and a static `items` array, which is the normal
61
+ * case, pays it once at startup.
62
+ */
63
+ /**
64
+ * Captured PNGs, keyed by icon identity. Module scope: see above.
65
+ *
66
+ * SUCCESSES ONLY. An earlier version also stored failures here, as an empty
67
+ * string, to stop an uncapturable icon being retried on every render. That
68
+ * was a trap: this map outlives every mount AND survives Fast Refresh, so a
69
+ * failure recorded once was permanent for the life of the JS context. Fixing
70
+ * the cause — an icon component that did not forward its ref — then changed
71
+ * nothing, because the poisoned entry was still there and the icon was never
72
+ * attempted again. Failures are tracked per mount instead; see `failed`.
73
+ */
74
+ const cache = new Map();
75
+ /**
76
+ * Stable ids for component types, so a cache key can name "this icon
77
+ * component" without stringifying a function.
78
+ *
79
+ * Weak, because the key must not be the thing that keeps a lazily-imported
80
+ * icon module alive.
81
+ */
82
+ const typeIds = new WeakMap();
83
+ let nextTypeId = 0;
84
+ const typeId = (type) => {
85
+ if (typeof type === 'string')
86
+ return type;
87
+ if (typeof type !== 'function' && typeof type !== 'object')
88
+ return 'anon';
89
+ if (type === null)
90
+ return 'anon';
91
+ const existing = typeIds.get(type);
92
+ if (existing)
93
+ return existing;
94
+ const id = `t${nextTypeId++}`;
95
+ typeIds.set(type, id);
96
+ return id;
97
+ };
98
+ /**
99
+ * OPAQUE BLACK, and the colour genuinely does not matter.
100
+ *
101
+ * The capture is handed to UIKit as a TEMPLATE image: the alpha channel is
102
+ * the shape and the system chooses the colour. What does matter is that the
103
+ * colour is RESOLVABLE — lucide defaults `color` to the literal string
104
+ * `"currentColor"`, which resolves against the `<Svg>`'s own `color` prop, and
105
+ * with nothing to resolve against the glyph rasterises empty. Setting `color`
106
+ * on the root is what gives `currentColor` a value.
107
+ */
108
+ const RASTER_COLOR = '#000000';
109
+ /**
110
+ * The dimension to ask `toDataURL` for, in whichever unit this platform means
111
+ * by it. See the long note at the call site for why they disagree.
112
+ */
113
+ const captureSize = (size) => react_native_1.Platform.OS === 'android' ? Math.round(react_native_1.PixelRatio.get() * size) : size;
114
+ /** Props only ever serialised for the cache key, never compared deeply. */
115
+ const stableStringify = (value) => {
116
+ if (value === null || typeof value !== 'object') {
117
+ // A function in props cannot be serialised, and two renders produce two
118
+ // identities. Collapse it to its type: a caller whose icon varies by a
119
+ // callback should pass an explicit `key`.
120
+ return typeof value === 'function' ? 'fn' : String(value);
121
+ }
122
+ if (Array.isArray(value)) {
123
+ return `[${value.map(stableStringify).join(',')}]`;
124
+ }
125
+ const record = value;
126
+ const keys = Object.keys(record).sort();
127
+ return `{${keys
128
+ .map(k => `${k}:${stableStringify(record[k])}`)
129
+ .join(',')}}`;
130
+ };
131
+ /** True for the two icon forms that have to be drawn before iOS can use them. */
132
+ const needsRaster = (icon) => typeof icon === 'function' || (0, react_1.isValidElement)(icon);
133
+ const cacheKey = (item, size) => {
134
+ const { icon } = item;
135
+ if (!needsRaster(icon))
136
+ return null;
137
+ const base = item.key
138
+ ? `k:${item.key}`
139
+ : typeof icon === 'function'
140
+ ? `f:${typeId(icon)}`
141
+ : `e:${typeId(icon.type)}:${stableStringify(icon.props)}`;
142
+ return `${base}|${size}`;
143
+ };
144
+ /**
145
+ * Resolve an icon to the element that should actually be drawn, sized and
146
+ * coloured for capture.
147
+ */
148
+ const rasterElement = (icon, size) => {
149
+ var _a, _b, _c, _d, _e;
150
+ if (typeof icon === 'function') {
151
+ /*
152
+ ALWAYS THE UNSELECTED FACE. UIKit owns the selected appearance: it tints
153
+ the one template image it was given. Capturing the selected face too
154
+ would produce a second artwork fighting the system's own treatment —
155
+ which is also why `tintable` exists for icons that should opt out.
156
+ */
157
+ return icon({ selected: false, color: RASTER_COLOR, size });
158
+ }
159
+ if (!(0, react_1.isValidElement)(icon))
160
+ return null;
161
+ const props = ((_a = icon.props) !== null && _a !== void 0 ? _a : {});
162
+ return (0, react_1.cloneElement)(icon, {
163
+ // Only filled in where the caller left them out, so an icon that sets its
164
+ // own size or colours keeps them.
165
+ size: (_b = props.size) !== null && _b !== void 0 ? _b : size,
166
+ width: (_c = props.width) !== null && _c !== void 0 ? _c : size,
167
+ height: (_d = props.height) !== null && _d !== void 0 ? _d : size,
168
+ color: (_e = props.color) !== null && _e !== void 0 ? _e : RASTER_COLOR,
169
+ });
170
+ };
171
+ /**
172
+ * How long to wait for a capture before re-issuing it, and how many times.
173
+ *
174
+ * Eight tries at 100ms is 800ms of patience before an icon is written off,
175
+ * which is generous for something that normally lands on the first frame and
176
+ * still short enough that a genuinely uncapturable icon does not hold the
177
+ * off-screen host mounted for the session.
178
+ */
179
+ const RETRY_MS = 100;
180
+ const MAX_TRIES = 8;
181
+ /**
182
+ * One off-screen icon, captured once.
183
+ *
184
+ * `toDataURL` needs the NATIVE view to exist and, on Android, to have been
185
+ * drawn at least once — neither of which is true when the effect first runs:
186
+ * React has committed the tree, but the native view is mounted and laid out a
187
+ * frame later. Hence the frame of delay.
188
+ *
189
+ * THE WATCHDOG IS NOT BELT-AND-BRACES, it is the only thing covering the worst
190
+ * failure mode. On Android `SvgViewModule.toDataURL` checks `notRendered()`
191
+ * and, if the view has not drawn yet, parks the request as a task to be run
192
+ * from the next `onDraw` — and returns WITHOUT invoking the callback. So a
193
+ * retry driven from inside the callback cannot fire: nothing ever calls it.
194
+ * Re-issuing the whole request on a timer is what breaks that deadlock, and
195
+ * the attempt cap is what stops it running forever if the icon simply cannot
196
+ * be drawn.
197
+ */
198
+ const Capture = ({ cacheKey: key, node, size, onCaptured }) => {
199
+ const ref = (0, react_1.useRef)(null);
200
+ /**
201
+ * Survives effect re-runs on purpose.
202
+ *
203
+ * `cancelled` below is per-run, so a re-run restarts a capture that has not
204
+ * landed. This one is per-COMPONENT, so a capture that already reported is
205
+ * never reported twice — which it would be if both flags were the same ref,
206
+ * and which the earlier version of this file got wrong in the other
207
+ * direction: a cleanup that set the shared flag killed every subsequent
208
+ * attempt, so any re-render before the first capture landed meant no glyph
209
+ * ever appeared.
210
+ */
211
+ const reported = (0, react_1.useRef)(false);
212
+ (0, react_1.useEffect)(() => {
213
+ let cancelled = false;
214
+ let tries = 0;
215
+ let watchdog;
216
+ let frame = 0;
217
+ const report = (dataUri) => {
218
+ if (cancelled || reported.current)
219
+ return;
220
+ reported.current = true;
221
+ if (watchdog)
222
+ clearTimeout(watchdog);
223
+ onCaptured(key, dataUri);
224
+ };
225
+ const issue = () => {
226
+ if (cancelled || reported.current)
227
+ return;
228
+ if (tries >= MAX_TRIES) {
229
+ report(null);
230
+ return;
231
+ }
232
+ tries += 1;
233
+ const svg = ref.current;
234
+ if (!svg || typeof svg.toDataURL !== 'function') {
235
+ /*
236
+ Either the native view is not up yet, or this is not an <Svg> root at
237
+ all — the usual cause of the latter being an icon wrapped in a <View>,
238
+ where the ref lands on the wrapper and the SVG underneath is
239
+ unreachable. Both are retried, because the first resolves itself and
240
+ the second costs only the attempt budget before falling through to a
241
+ reported miss.
242
+ */
243
+ watchdog = setTimeout(issue, RETRY_MS);
244
+ return;
245
+ }
246
+ watchdog = setTimeout(issue, RETRY_MS);
247
+ svg.toDataURL((base64) => {
248
+ if (base64) {
249
+ /*
250
+ `toDataURL` yields BARE base64, not a data URI — the name is a
251
+ long-standing misnomer in react-native-svg. The prefix is added
252
+ here so the native side receives something it recognises as an
253
+ image source.
254
+ */
255
+ report(`data:image/png;base64,${base64}`);
256
+ }
257
+ // An empty result is left to the watchdog rather than retried here,
258
+ // so there is one retry path instead of two that can race.
259
+ },
260
+ /*
261
+ THE UNITS DIFFER BY PLATFORM, and getting it wrong fails quietly in
262
+ two different ways. Hence `captureSize`.
263
+
264
+ iOS takes POINTS. The renderer is a `UIGraphicsImageRenderer` at the
265
+ screen's scale, so a 24-point request yields a 24x24pt / 72x72px PNG
266
+ on a 3x device; PNG carries no scale, so the native side decodes it
267
+ with `UIScreen.main.scale` and the two cancel out. Asking for
268
+ `size * pixelRatio` here would double-apply the scale and draw the
269
+ glyph three times too large.
270
+
271
+ Android takes PIXELS. `SvgView.toDataURL(w, h)` allocates a bitmap of
272
+ exactly w by h pixels and then draws the SVG in the VIEW's own
273
+ coordinate space, which is already in pixels — so a 24-pixel bitmap
274
+ on a 3x device captures the top-left ninth of a 72-pixel glyph and
275
+ discards the rest. The bitmap has to be the full pixel size, and the
276
+ native side scales it back down to `size` dp when it draws.
277
+ */
278
+ { width: captureSize(size), height: captureSize(size) });
279
+ };
280
+ frame = requestAnimationFrame(issue);
281
+ return () => {
282
+ cancelled = true;
283
+ if (watchdog)
284
+ clearTimeout(watchdog);
285
+ cancelAnimationFrame(frame);
286
+ };
287
+ }, [key, size, onCaptured]);
288
+ return (0, react_1.cloneElement)(node, { ref });
289
+ };
290
+ const styles = react_native_1.StyleSheet.create({
291
+ /**
292
+ * OFF-SCREEN, not invisible, and NOT CLIPPED.
293
+ *
294
+ * `opacity: 0` and `display: 'none'` are both tempting and both wrong: the
295
+ * first relies on the renderer still drawing a fully transparent subtree,
296
+ * and the second detaches the native view so there is nothing left to
297
+ * capture. Moving it out of the viewport keeps a real, laid-out native view
298
+ * that the user cannot see.
299
+ *
300
+ * No size and no `overflow: 'hidden'` either, which an earlier version had.
301
+ * Pinning the host to 1x1 and clipping is the obvious way to keep it out of
302
+ * the way, but on Android a capture is only possible once the SVG has been
303
+ * drawn at least once — so clipping the icons out of the host is clipping
304
+ * away the very thing being waited on. Without a size the host sizes itself
305
+ * to its content, and being off-screen is enough on its own.
306
+ */
307
+ host: {
308
+ position: 'absolute',
309
+ left: -10000,
310
+ top: -10000,
311
+ },
312
+ });
313
+ /**
314
+ * Capture every React-element icon in `items`, memoised by icon identity.
315
+ *
316
+ * Returns the captured sources plus the off-screen host that does the
317
+ * capturing — the caller has to render the host, since a hook cannot mount
318
+ * views on its own.
319
+ */
320
+ const useRasterisedIcons = (items, size) => {
321
+ const keys = (0, react_1.useMemo)(() => items.map(item => cacheKey(item, size)), [items, size]);
322
+ /**
323
+ * Captures that landed during THIS mount.
324
+ *
325
+ * The module cache is the source of truth and survives unmounting, but a
326
+ * write to it is invisible to the reconciler. This mirror is what actually
327
+ * triggers the re-render; it is only ever added to, and it is seeded from
328
+ * nothing because a warm cache needs no re-render — `sources` reads it
329
+ * directly on the first pass.
330
+ */
331
+ const [captured, setCaptured] = (0, react_1.useState)({});
332
+ /**
333
+ * Icons that could not be captured DURING THIS MOUNT.
334
+ *
335
+ * Held in a ref rather than in the module cache so the scope is right in
336
+ * both directions: within a mount an icon is attempted once, so a glyph that
337
+ * genuinely cannot be drawn does not spin; across mounts the slate is clean,
338
+ * so remounting the bar — or a Fast Refresh that fixed the icon — gets
339
+ * another go. A permanent record of failure is what made a fixed icon stay
340
+ * broken until the app was killed.
341
+ */
342
+ const failed = (0, react_1.useRef)(new Set());
343
+ const onCaptured = (0, react_1.useCallback)((key, dataUri) => {
344
+ if (dataUri) {
345
+ cache.set(key, dataUri);
346
+ }
347
+ else {
348
+ failed.current.add(key);
349
+ if (__DEV__) {
350
+ /*
351
+ LOUD, because the failure is otherwise invisible: the item renders
352
+ with its title and no glyph, which reads as a styling problem rather
353
+ than a capture that never happened.
354
+ */
355
+ console.warn(`[lq-bottom-bar] Could not rasterise the icon for "${key}". ` +
356
+ 'The icon must be a react-native-svg <Svg> element, or a component ' +
357
+ 'that forwards its ref to one — a plain function component drops ' +
358
+ 'the ref and cannot be captured. Wrap it in React.forwardRef.');
359
+ }
360
+ }
361
+ setCaptured(prev => ({ ...prev, [key]: dataUri !== null && dataUri !== void 0 ? dataUri : '' }));
362
+ }, []);
363
+ const sources = (0, react_1.useMemo)(() => keys.map(key => {
364
+ var _a;
365
+ if (!key)
366
+ return null;
367
+ return (_a = cache.get(key)) !== null && _a !== void 0 ? _a : null;
368
+ }),
369
+ // `captured` is what makes this re-run; the cache it reads is module state.
370
+ // eslint-disable-next-line react-hooks/exhaustive-deps
371
+ [keys, captured]);
372
+ const pending = (0, react_1.useMemo)(() => keys
373
+ .map((key, index) => ({ key, index }))
374
+ .filter((entry) => entry.key !== null &&
375
+ !cache.has(entry.key) &&
376
+ !failed.current.has(entry.key)),
377
+ // eslint-disable-next-line react-hooks/exhaustive-deps
378
+ [keys, captured]);
379
+ const host = pending.length === 0 ? null : (react_1.default.createElement(react_native_1.View, { style: styles.host, pointerEvents: "none", collapsable: false }, pending.map(({ key, index }) => {
380
+ const node = rasterElement(items[index].icon, size);
381
+ if (!node)
382
+ return null;
383
+ return (
384
+ /*
385
+ `onCaptured` IS PASSED AS-IS, not wrapped in an arrow.
386
+
387
+ An inline `dataUri => onCaptured(key, dataUri)` is a new function
388
+ identity on every render, which lands in `Capture`'s effect deps
389
+ and re-runs the effect — tearing down an in-flight capture on
390
+ every parent render. The key travels as a prop instead so the
391
+ callback can stay stable.
392
+ */
393
+ react_1.default.createElement(Capture, { key: key, cacheKey: key, node: node, size: size, onCaptured: onCaptured }));
394
+ })));
395
+ return { sources, host };
396
+ };
397
+ exports.useRasterisedIcons = useRasterisedIcons;
398
+ //# sourceMappingURL=rasterise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rasterise.js","sourceRoot":"","sources":["../../src/rasterise.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { ImageSourcePropType, StyleProp, ViewProps, ViewStyle } from 'react-native';
3
+ /**
4
+ * What an item's icon can be.
5
+ *
6
+ * The union is wide because the two platforms want opposite things and the
7
+ * caller should not have to care which.
8
+ *
9
+ * A native `UITabBar` draws its own items and accepts only `UIImage`, so a
10
+ * React element has to BECOME an image before it reaches the bar. The JS
11
+ * Android bar has no such constraint and renders the element directly, at
12
+ * full fidelity. `src/rasterise.tsx` is the bridge between those two facts.
13
+ */
14
+ export type LQIcon =
15
+ /**
16
+ * A react-native-svg element — which is what a lucide icon is, under the
17
+ * hood. Rasterised once on iOS, rendered live on Android.
18
+ */
19
+ ReactElement
20
+ /**
21
+ * The same, but told whether it is selected. Preferred over a bare element
22
+ * when the icon changes shape (not just tint) between states: an outline
23
+ * glyph when idle and a filled one when active, which is what this app's
24
+ * own set does.
25
+ *
26
+ * iOS calls this ONCE, with `selected: false`, because UIKit owns the
27
+ * selected appearance — see `tintable`.
28
+ */
29
+ | ((state: LQIconState) => ReactElement)
30
+ /** `require('./home.png')`, or `{ uri }`. */
31
+ | ImageSourcePropType
32
+ /** A name in the app's own asset catalogue. iOS only. */
33
+ | {
34
+ name: string;
35
+ }
36
+ /** An SF Symbol. iOS only; ignored on Android. */
37
+ | {
38
+ sfSymbol: string;
39
+ };
40
+ export interface LQIconState {
41
+ selected: boolean;
42
+ /** `selectedColor` when selected, `unselectedColor` otherwise. */
43
+ color: string;
44
+ size: number;
45
+ }
46
+ export interface LQBottomBarItem {
47
+ /** Shown under the glyph unless `labeled` is false. */
48
+ title?: string;
49
+ icon: LQIcon;
50
+ /**
51
+ * A STABLE identity for this item's icon, and the cache key the
52
+ * rasteriser memoises on.
53
+ *
54
+ * Without it the key is derived from the icon's component type and its
55
+ * props, which is correct but costs a serialisation per render and misses
56
+ * when a prop is a function or a style object. Pass this whenever the item
57
+ * list is static, which it almost always is.
58
+ */
59
+ key?: string;
60
+ /**
61
+ * Whether UIKit may TINT this glyph, iOS only. Default true.
62
+ *
63
+ * True renders the image as a template: the alpha channel is the shape and
64
+ * the system picks the colour, selected against unselected. That is what
65
+ * makes one artwork cover both states and what makes the glyph follow the
66
+ * platform's own selected-state treatment.
67
+ *
68
+ * Set it false for an icon whose own colours ARE the content — an avatar, a
69
+ * brand mark — which then looks identical in both states.
70
+ */
71
+ tintable?: boolean;
72
+ /** Accessibility label. Falls back to `title`. */
73
+ accessibilityLabel?: string;
74
+ }
75
+ export interface LQBottomBarProps {
76
+ items: LQBottomBarItem[];
77
+ /**
78
+ * Which item is lit. JS OWNS THIS, on both platforms: `onTabSelected` is a
79
+ * report, not a commit, so a press that should not switch tabs (one that
80
+ * opens a detail screen instead, say) cannot desync the bar.
81
+ */
82
+ selectedIndex: number;
83
+ /** Tint for the selected item. Leave unset for the system default. */
84
+ selectedColor?: string;
85
+ /** Tint for everything else. */
86
+ unselectedColor?: string;
87
+ /** False hides the titles and re-centres the glyphs. Default true. */
88
+ labeled?: boolean;
89
+ /** Glyph size in points. Default 24. */
90
+ iconSize?: number;
91
+ onTabSelected?: (index: number) => void;
92
+ style?: StyleProp<ViewStyle>;
93
+ /**
94
+ * Forwarded to the native view, because a bar is very often absolutely
95
+ * positioned over a scrollable page.
96
+ *
97
+ * `"box-none"` is the useful value there: the bar's own items stay tappable
98
+ * while the empty space around them — the safe-area strip below, the gap
99
+ * either side of an inset pill — passes touches through to the content
100
+ * underneath instead of swallowing them.
101
+ */
102
+ pointerEvents?: ViewProps['pointerEvents'];
103
+ /**
104
+ * Android only: blur strength behind the bar, 0 disables it and leaves the
105
+ * flat `androidBackgroundColor` scrim. Default 20.
106
+ */
107
+ blurAmount?: number;
108
+ /**
109
+ * Android only: the material's TINT, painted over the blurred backdrop.
110
+ *
111
+ * That order is how UIKit composes a material — blur first, then a
112
+ * translucent colour on top — and it is why this must stay translucent. An
113
+ * opaque value stops being a tint and becomes a lid: the blur is still
114
+ * computed, still costs a software draw of the tree every frame, and is
115
+ * completely hidden behind it.
116
+ */
117
+ androidBackgroundColor?: string;
118
+ }
119
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EACV,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;GAUG;AACH,MAAM,MAAM,MAAM;AAChB;;;GAGG;AACD,YAAY;AACd;;;;;;;;GAQG;GACD,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,YAAY,CAAC;AACxC,6CAA6C;GAC3C,mBAAmB;AACrB,yDAAyD;GACvD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,kDAAkD;GAChD;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzB,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,kDAAkD;IAClD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,eAAe,EAAE,CAAC;IAEzB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IAE3C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,67 @@
1
1
  {
2
2
  "name": "@honeypathkar/react-native-lq-bottom-bar",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "The real iOS UITabBar (liquid glass on iOS 26) and a matching blurred Android bar, taking React icons rather than only images",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "lib/commonjs/index.js",
9
+ "module": "lib/commonjs/index.js",
10
+ "react-native": "src/index.tsx",
11
+ "source": "src/index.tsx",
12
+ "types": "lib/commonjs/index.d.ts",
13
+ "files": [
14
+ "src",
15
+ "lib",
16
+ "ios",
17
+ "android/src",
18
+ "android/build.gradle",
19
+ "react-native-lq-bottom-bar.podspec",
20
+ "README.md",
21
+ "!lib/tsconfig.tsbuildinfo"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc --build",
25
+ "clean": "rm -rf lib",
26
+ "prepare": "npm run build"
27
+ },
28
+ "keywords": [
29
+ "react-native",
30
+ "ios",
31
+ "android",
32
+ "tab-bar",
33
+ "bottom-bar",
34
+ "uitabbar",
35
+ "liquid-glass",
36
+ "blur",
37
+ "lucide",
38
+ "svg"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/honeypathkar/react-native-components.git",
43
+ "directory": "react-native-lq-bottom-bar"
44
+ },
45
+ "homepage": "https://github.com/honeypathkar/react-native-components/tree/master/react-native-lq-bottom-bar#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/honeypathkar/react-native-components/issues"
48
+ },
49
+ "author": "honeypathkar",
50
+ "license": "MIT",
51
+ "peerDependencies": {
52
+ "react": "*",
53
+ "react-native": "*",
54
+ "react-native-svg": ">=13.0.0"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "react-native-svg": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@types/react": "^19.0.0",
63
+ "react": "19.2.0",
64
+ "react-native": "0.83.1",
65
+ "typescript": "^5.0.0"
66
+ }
67
+ }
@@ -0,0 +1,27 @@
1
+ require "json"
2
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
3
+
4
+ Pod::Spec.new do |s|
5
+ s.name = "react-native-lq-bottom-bar"
6
+ s.version = package["version"]
7
+ s.summary = package["description"]
8
+ s.license = package["license"]
9
+ s.authors = { "honeypathkar" => "tech@yekuminc.com" }
10
+ s.homepage = "https://github.com/honeypathkar/react-native-lq-bottom-bar"
11
+ s.platforms = { :ios => "15.0" }
12
+ s.source = { :git => "https://github.com/honeypathkar/react-native-lq-bottom-bar.git", :tag => "#{s.version}" }
13
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
14
+ s.swift_version = "5.0"
15
+
16
+ # React Native's own helper, not a bare `React-Core` dependency. With the
17
+ # new architecture on, a pod that touches React headers needs the whole
18
+ # Fabric/JSI header surface and its flags; `React-Core` alone leaves
19
+ # `jsi/jsi.h` off the search path and the failure then surfaces inside
20
+ # React's OWN targets, which looks like a broken app rather than a bad
21
+ # podspec.
22
+ if respond_to?(:install_modules_dependencies, true)
23
+ install_modules_dependencies(s)
24
+ else
25
+ s.dependency "React-Core"
26
+ end
27
+ end