@qumra/fanar-native 0.1.2 → 0.1.4

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.
@@ -70,7 +70,7 @@ export function StepRow({ icon, title, why, done, action, onPress, style }) {
70
70
  const inner = (_jsxs(_Fragment, { children: [done ? (_jsx(View, { style: [
71
71
  styles.stepIcon,
72
72
  { borderRadius: theme.radius.field, backgroundColor: theme.color.brand },
73
- ], children: _jsx(Check, { size: 17, strokeWidth: 3, color: "#ffffff" }) })) : brand ? (_jsx(QumraIcon, { name: brand, size: 34 })) : (_jsx(View, { style: [
73
+ ], children: _jsx(Check, { size: 17, strokeWidth: 3, color: "#ffffff" }) })) : brand ? (_jsx(View, { style: styles.stepIcon, children: _jsx(QumraIcon, { name: brand, size: 34 }) })) : (_jsx(View, { style: [
74
74
  styles.stepIcon,
75
75
  { borderRadius: theme.radius.field, backgroundColor: theme.color.soft },
76
76
  ], children: Lucide ? _jsx(Lucide, { size: 18, strokeWidth: 2, color: theme.color.brand }) : null })), _jsxs(View, { style: styles.rowText, children: [_jsx(Text, { size: 14.5, weight: "extraBold", color: done ? 'muted' : 'ink', align: "start", style: done ? styles.struck : { textAlign: 'left' }, children: title }), why ? (_jsx(Text, { size: 12.5, style: { textAlign: 'left' }, color: "muted", align: "start", leading: "relaxed", lines: 1, children: why })) : null] }), action] }));
package/lib/icons.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { type StyleProp, type ViewStyle } from 'react-native';
3
3
  import { AlertTriangle, ArrowLeft, ArrowRight, BarChart3, Bell, Bot, Check, CheckCheck, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Copy, ExternalLink, Globe, Home, Info, Lock, Menu, Minus, Plus, Search, Share2, Sparkles, Star, Undo2, X, type LucideIcon } from 'lucide-react-native';
4
4
  export type { LucideIcon };
5
+ export declare function uiIconFor(name: string): string | undefined;
5
6
  export declare function qumraIconFor(name: string): string | undefined;
6
7
  export declare function icon(name: string): LucideIcon;
7
8
  export declare function hasIcon(name: string): boolean;
package/lib/icons.js CHANGED
@@ -374,6 +374,59 @@ function qumraAs(qumraName) {
374
374
  wrapped[qumraName] = Wrapped;
375
375
  return wrapped[qumraName];
376
376
  }
377
+ const stemOf = (name) => name.replace(/-(outline|sharp)$/, '');
378
+ const UI_FOR = {
379
+ add: 'plus', 'add-circle': 'plus', plus: 'plus', 'folder-plus': 'plus', 'package-plus': 'plus',
380
+ 'person-add': 'user-plus', remove: 'close', close: 'close', 'close-circle': 'close', x: 'close',
381
+ checkmark: 'check', 'checkmark-circle': 'check', 'checkmark-done': 'check', check: 'check',
382
+ checkbox: 'check', trash: 'trash', 'trash-2': 'trash', create: 'pencil', pencil: 'pencil',
383
+ brush: 'pencil', 'color-wand': 'sparkle', copy: 'copy', save: 'save', download: 'save',
384
+ 'cloud-download': 'save', 'cloud-upload': 'publish', print: 'print', send: 'send',
385
+ 'share-social': 'share', 'share-2': 'share', search: 'search', filter: 'filter',
386
+ funnel: 'filter', options: 'sliders', sync: 'repeat', reload: 'repeat', refresh: 'reset',
387
+ 'refresh-circle': 'reset', scan: 'search', stop: 'stop', 'pause-circle': 'stop', play: 'live',
388
+ 'play-circle': 'live', 'log-out': 'logout', exit: 'logout', open: 'external',
389
+ 'external-link': 'external', link: 'link', unlink: 'unlink', expand: 'expand',
390
+ contract: 'collapse', resize: 'expand',
391
+ 'alert-circle': 'alert', 'alert-triangle': 'alert', warning: 'alert', 'help-circle': 'alert',
392
+ 'information-circle': 'alert', 'life-buoy': 'alert', ban: 'ban', 'shield-checkmark': 'shield-check',
393
+ 'shield-half': 'shield', 'lock-closed': 'lock', key: 'key', 'finger-print': 'key',
394
+ eye: 'eye', 'eye-off': 'eye-off', star: 'star', crown: 'crown', diamond: 'crown',
395
+ sparkles: 'sparkle', rocket: 'rocket', flash: 'bolt', flame: 'flame', bulb: 'bulb',
396
+ storefront: 'store', business: 'building', cube: 'box', 'package-open': 'box',
397
+ 'bag-handle': 'bag', bag: 'bag', cart: 'cart', shoppingcart: 'cart', pricetag: 'tag',
398
+ pricetags: 'tag', gift: 'tag', ticket: 'tag', receipt: 'receipt', card: 'card',
399
+ cash: 'money', payments: 'money', wallet: 'wallet', calculator: 'sigma',
400
+ person: 'user', 'person-circle': 'user', user: 'user', people: 'users', customers: 'users',
401
+ partners: 'users', car: 'truck', barcode: 'hash', keypad: 'hash',
402
+ document: 'file', documents: 'file', 'document-text': 'file', reader: 'file', sheet: 'sheet',
403
+ folder: 'folder', library: 'layers', albums: 'layers', layers: 'layers', book: 'note',
404
+ journal: 'note', chatbubble: 'note', chatbubbles: 'note', text: 'text', 'code-slash': 'code',
405
+ terminal: 'code', image: 'image-plus', images: 'image-plus', camera: 'image-plus',
406
+ 'camera-off': 'image-off', videocam: 'film', film: 'film', shapes: 'template',
407
+ 'layout-grid': 'grid', grid: 'grid', apps: 'grid', widgets: 'template', list: 'rows',
408
+ 'reorder-three': 'rows', 'drag-indicator': 'grip', archive: 'archive',
409
+ 'bar-chart': 'chart', 'stats-chart': 'chart', 'pie-chart': 'chart', analytics: 'chart',
410
+ pulse: 'chart', speedometer: 'chart', 'trending-up': 'trend-up', 'trending-down': 'trend-down',
411
+ settings: 'gear', construct: 'gear', build: 'gear', hammer: 'gear', 'color-palette': 'palette',
412
+ globe: 'globe', earth: 'globe', language: 'language', server: 'database', cloud: 'database',
413
+ 'cloud-offline': 'database', desktop: 'desktop', laptop: 'desktop', 'phone-portrait': 'mobile',
414
+ 'tablet-portrait': 'tablet', radio: 'plug', bot: 'sparkle',
415
+ mail: 'mail', 'mail-open': 'mail', 'mail-unread': 'mail', call: 'phone', phone: 'phone',
416
+ 'phone-call': 'phone', headset: 'phone', megaphone: 'megaphone', notifications: 'bell',
417
+ 'notifications-off': 'bell', bell: 'bell', time: 'clock', clock: 'clock',
418
+ calendar: 'calendar', 'calendar-clear': 'calendar', location: 'pin', 'map-marker': 'pin',
419
+ map: 'pin', navigate: 'cursor', pin: 'pin', flag: 'thumbtack', menu: 'menu',
420
+ 'ellipsis-vertical': 'more', 'ellipsis-horizontal': 'more', more: 'more',
421
+ 'swap-vertical': 'sort', sun: 'live', moon: 'live',
422
+ 'arrow-back': 'arrow-left', 'arrow-forward': 'arrow-right',
423
+ 'arrow-undo': 'undo', 'arrow-redo': 'redo',
424
+ 'chevron-down': 'chevron-down', 'chevron-small-down': 'chevron-down', 'chevron-up': 'chevron-up',
425
+ };
426
+ export function uiIconFor(name) {
427
+ const tool = UI_FOR[stemOf(name)];
428
+ return tool ? `ui-${tool}` : undefined;
429
+ }
377
430
  export function qumraIconFor(name) {
378
431
  return QUMRA_FOR[name];
379
432
  }
@@ -381,10 +434,13 @@ export function icon(name) {
381
434
  const brand = QUMRA_FOR[name];
382
435
  if (brand)
383
436
  return qumraAs(brand);
437
+ const tool = uiIconFor(name);
438
+ if (tool)
439
+ return qumraAs(tool);
384
440
  return MAP[name] ?? ALIAS[name] ?? Home;
385
441
  }
386
442
  export function hasIcon(name) {
387
- return name in QUMRA_FOR || name in MAP || name in ALIAS;
443
+ return name in QUMRA_FOR || !!uiIconFor(name) || name in MAP || name in ALIAS;
388
444
  }
389
445
  export const ICON_SIZE = {
390
446
  xs: 12,
package/lib/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { TONE_SOFT, TONE_SOLID, type Tone, type ToneColors } from './lib/tone';
5
5
  export { toLatinDigits, toArabicDigits, groupDigits } from './lib/digits';
6
6
  export { usePressScale, useEnter, useSkeletonPulse, EASE_OUT, EASE_IN_OUT } from './lib/motion';
7
7
  export { hitSlopFor, HIT_SLOP_SM, TOUCH_MIN } from './lib/a11y';
8
- export { icon, hasIcon, Icon, qumraIconFor, snapIconSize, ICON_SIZE, ICON_STROKE, type LucideIcon, type IconProps, type IconSize, } from './icons';
8
+ export { icon, hasIcon, Icon, qumraIconFor, uiIconFor, snapIconSize, ICON_SIZE, ICON_STROKE, type LucideIcon, type IconProps, type IconSize, } from './icons';
9
9
  export { QumraIcon, hasQumraIcon, QUMRA_ICONS, type QumraIconProps, type QumraIconName, type QumraIconSpec, } from './qumra/QumraIcon';
10
10
  export { NavIcon, type NavIconProps } from './qumra/NavIcon';
11
11
  export { art, hasArt, BRAND, ART, type BrandName, type ArtName } from './art';
package/lib/index.js CHANGED
@@ -5,7 +5,7 @@ export { TONE_SOFT, TONE_SOLID } from './lib/tone';
5
5
  export { toLatinDigits, toArabicDigits, groupDigits } from './lib/digits';
6
6
  export { usePressScale, useEnter, useSkeletonPulse, EASE_OUT, EASE_IN_OUT } from './lib/motion';
7
7
  export { hitSlopFor, HIT_SLOP_SM, TOUCH_MIN } from './lib/a11y';
8
- export { icon, hasIcon, Icon, qumraIconFor, snapIconSize, ICON_SIZE, ICON_STROKE, } from './icons';
8
+ export { icon, hasIcon, Icon, qumraIconFor, uiIconFor, snapIconSize, ICON_SIZE, ICON_STROKE, } from './icons';
9
9
  export { QumraIcon, hasQumraIcon, QUMRA_ICONS, } from './qumra/QumraIcon';
10
10
  export { NavIcon } from './qumra/NavIcon';
11
11
  export { art, hasArt, BRAND, ART } from './art';
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
3
  import Svg, { Circle, ClipPath, Defs, Ellipse, G, LinearGradient, Path, RadialGradient, Rect, Stop, Text as SvgText, } from 'react-native-svg';
4
4
  import { QUMRA_ICONS } from './data.generated';
5
+ import { useFanar } from '../theme/context';
5
6
  const TAGS = {
6
7
  svg: Svg,
7
8
  g: G,
@@ -34,7 +35,8 @@ function grayscale(value) {
34
35
  const c = l.toString(16).padStart(2, '0');
35
36
  return `#${c}${c}${c}`;
36
37
  }
37
- function build(node, uid, key, tint) {
38
+ const CURRENT = 'currentColor';
39
+ function build(node, uid, key, tint, current) {
38
40
  const [tag, props, kids] = node;
39
41
  const Cmp = TAGS[tag];
40
42
  if (!Cmp)
@@ -49,7 +51,9 @@ function build(node, uid, key, tint) {
49
51
  v = `${v}-${uid}`;
50
52
  else if (typeof v === 'string' && v.indexOf('url(#') !== -1)
51
53
  v = uniquify(v, uid);
52
- if (tint && isPaint(k) && v !== 'none')
54
+ if (isPaint(k) && v === CURRENT)
55
+ v = current ?? v;
56
+ if (tint && isPaint(k) && v !== 'none' && v !== CURRENT)
53
57
  v = flat ?? grayscale(v);
54
58
  p[k] = v;
55
59
  }
@@ -59,7 +63,7 @@ function build(node, uid, key, tint) {
59
63
  if (p.strokeOpacity !== undefined)
60
64
  p.strokeOpacity = '1';
61
65
  }
62
- const children = kids?.map((c, i) => build(c, uid, i, tint)).filter(Boolean);
66
+ const children = kids?.map((c, i) => build(c, uid, i, tint, current)).filter(Boolean);
63
67
  return React.createElement(Cmp, { key, ...p }, children?.length ? children : undefined);
64
68
  }
65
69
  function badge(count) {
@@ -74,11 +78,13 @@ function badge(count) {
74
78
  return (_jsxs(G, { children: [_jsx(Rect, { x: x, y: 2.2, width: w, height: 12.4, rx: 6.2, fill: "#E8A94F", stroke: "#F2F7F8", strokeWidth: 1.4 }), _jsx(SvgText, { x: x + w / 2, y: 8.4, dy: fs * 0.35, textAnchor: "middle", fill: "#FFFFFF", fontSize: fs, fontWeight: "700", children: s })] }, "qi-count"));
75
79
  }
76
80
  export function QumraIcon({ name, size = 32, mono, active, color, count, label, onPress, }) {
81
+ const { theme } = useFanar();
77
82
  const spec = QUMRA_ICONS[name];
78
83
  const uid = React.useId().replace(/[^a-zA-Z0-9]/g, '');
79
84
  const dimmed = !!mono && !active;
80
85
  const tint = dimmed ? color ?? 'gray' : undefined;
81
- const children = React.useMemo(() => (spec ? spec.tree.map((n, i) => build(n, uid, i, tint)) : []), [spec, uid, tint]);
86
+ const current = color ?? theme.color.ink;
87
+ const children = React.useMemo(() => (spec ? spec.tree.map((n, i) => build(n, uid, i, tint, current)) : []), [spec, uid, tint, current]);
82
88
  if (!spec) {
83
89
  if (__DEV__)
84
90
  console.warn(`[qumra-icons] لا توجد أيقونة بالاسم «${name}»`);