@rpg-engine/long-bow 0.8.212 → 0.8.214

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.212",
3
+ "version": "0.8.214",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "build": "tsdx build",
25
25
  "test": "tsdx test --passWithNoTests",
26
26
  "lint": "tsdx lint",
27
- "prepare": "echo skip",
27
+ "prepare": "tsdx build",
28
28
  "size": "size-limit",
29
29
  "analyze": "size-limit --why",
30
30
  "storybook": "start-storybook -p 6006",
@@ -236,7 +236,8 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
236
236
  if (onClose) onClose();
237
237
  }}
238
238
  isFullScreen={fullScreen}
239
- width="920px"
239
+ width="1050px"
240
+ minWidth="750px"
240
241
  cancelDrag="#MarketContainer, .rpgui-dropdown-imp, input, .empty-slot, button"
241
242
  scale={scale}
242
243
  >
@@ -49,6 +49,10 @@ export interface IStoreProps {
49
49
  customHistoryContent?: React.ReactNode;
50
50
  /** When true the store renders full-screen (useful on mobile). */
51
51
  fullScreen?: boolean;
52
+ /** Override the DraggableContainer width (e.g. "90vw"). Defaults to "1000px". */
53
+ containerWidth?: string;
54
+ /** Override the DraggableContainer height (e.g. "80vh"). Defaults to "auto". */
55
+ containerHeight?: string;
52
56
  packsBadge?: string;
53
57
  featuredItems?: IFeaturedItem[];
54
58
  onQuickBuy?: (item: IProductBlueprint, quantity?: number) => void;
@@ -110,6 +114,8 @@ export const Store: React.FC<IStoreProps> = ({
110
114
  customWalletContent,
111
115
  customHistoryContent,
112
116
  fullScreen = false,
117
+ containerWidth,
118
+ containerHeight,
113
119
  packsTabLabel = 'Packs',
114
120
  packsBadge,
115
121
  featuredItems,
@@ -135,11 +141,18 @@ export const Store: React.FC<IStoreProps> = ({
135
141
  const defaultTabOrder: TabId[] = ['premium', 'packs', 'items'];
136
142
  const [selectedPack, setSelectedPack] = useState<IItemPack | null>(null);
137
143
  const [activeTab, setActiveTab] = useState<TabId>(() => {
138
- const initialTabs = (tabOrder ?? defaultTabOrder).filter(id => !(hidePremiumTab && id === 'premium'));
139
- if (defaultActiveTab && initialTabs.includes(defaultActiveTab)) {
144
+ const allTabIds: TabId[] = [
145
+ ...(tabOrder ?? defaultTabOrder),
146
+ ...(customCharactersContent ? ['characters' as TabId] : []),
147
+ ...(onRedeem ? ['redeem' as TabId] : []),
148
+ ...((onShowWallet || customWalletContent) ? ['wallet' as TabId] : []),
149
+ ...((onShowHistory || customHistoryContent) ? ['history' as TabId] : []),
150
+ ];
151
+ const validTabs = Array.from(new Set(allTabIds.filter(id => !(hidePremiumTab && id === 'premium'))));
152
+ if (defaultActiveTab && validTabs.includes(defaultActiveTab)) {
140
153
  return defaultActiveTab;
141
154
  }
142
- return initialTabs[0] ?? (hidePremiumTab ? 'items' : 'premium');
155
+ return validTabs[0] ?? (hidePremiumTab ? 'items' : 'premium');
143
156
  });
144
157
  const {
145
158
  cartItems,
@@ -355,7 +368,7 @@ export const Store: React.FC<IStoreProps> = ({
355
368
  },
356
369
  characters: {
357
370
  id: 'characters',
358
- title: 'Characters',
371
+ title: 'Char Trade',
359
372
  icon: <FaUsers size={16} />,
360
373
  content: customCharactersContent ?? null,
361
374
  },
@@ -397,9 +410,9 @@ export const Store: React.FC<IStoreProps> = ({
397
410
  <DraggableContainer
398
411
  title="Store"
399
412
  onCloseButton={onClose}
400
- width="850px"
401
- minWidth="600px"
402
- height="auto"
413
+ width={containerWidth ?? "1000px"}
414
+ minWidth="700px"
415
+ height={containerHeight ?? "auto"}
403
416
  type={RPGUIContainerTypes.Framed}
404
417
  cancelDrag="[class*='Store__Container'], [class*='CartView'], [class*='StoreItemDetails'], .close-button"
405
418
  isFullScreen={fullScreen}
@@ -417,7 +430,7 @@ export const Store: React.FC<IStoreProps> = ({
417
430
  onRemoveFromCart={handleRemoveFromCartTracked}
418
431
  onClose={closeCart}
419
432
  onPurchase={async () => {
420
- await handleCartPurchase(onPurchase);
433
+ handleCartPurchase(onPurchase);
421
434
  return true;
422
435
  }}
423
436
  atlasJSON={atlasJSON}
@@ -482,21 +495,23 @@ export const Store: React.FC<IStoreProps> = ({
482
495
  )}
483
496
  <MainContent>
484
497
  <HeaderRow>
485
- <Tabs
486
- options={availableTabIds.map(id => ({ id, label: tabsMap[id]?.title, icon: tabsMap[id]?.icon }))}
487
- activeTabId={activeTab}
488
- onTabChange={(tabId) => {
489
- const nextTab = tabId as TabId;
490
- setActiveTab(nextTab);
491
- if (onTabChange) {
492
- const itemCount = nextTab === 'items' ? filteredItems.items.length
493
- : nextTab === 'premium' ? filteredItems.premium.length
494
- : nextTab === 'packs' ? packs.length
495
- : 0;
496
- onTabChange(nextTab, itemCount);
497
- }
498
- }}
499
- />
498
+ <TabsFlexWrapper>
499
+ <Tabs
500
+ options={availableTabIds.map(id => ({ id, label: tabsMap[id]?.title, icon: tabsMap[id]?.icon }))}
501
+ activeTabId={activeTab}
502
+ onTabChange={(tabId) => {
503
+ const nextTab = tabId as TabId;
504
+ setActiveTab(nextTab);
505
+ if (onTabChange) {
506
+ const itemCount = nextTab === 'items' ? filteredItems.items.length
507
+ : nextTab === 'premium' ? filteredItems.premium.length
508
+ : nextTab === 'packs' ? packs.length
509
+ : 0;
510
+ onTabChange(nextTab, itemCount);
511
+ }
512
+ }}
513
+ />
514
+ </TabsFlexWrapper>
500
515
  <CartButtonWrapper>
501
516
  <CTAButton
502
517
  icon={<FaShoppingCart />}
@@ -548,15 +563,21 @@ const Container = styled.div`
548
563
 
549
564
  const HeaderRow = styled.div`
550
565
  display: flex;
551
- align-items: center;
566
+ align-items: flex-end;
552
567
  justify-content: space-between;
553
568
  margin-bottom: 0.25rem;
554
569
  padding-top: 10px;
555
570
  padding-right: 12px;
556
571
  `;
557
572
 
573
+ const TabsFlexWrapper = styled.div`
574
+ flex: 1;
575
+ min-width: 0;
576
+ `;
577
+
558
578
  const CartButtonWrapper = styled.div`
559
579
  position: relative;
580
+ flex-shrink: 0;
560
581
  `;
561
582
 
562
583
  const CartBadge = styled.div`
@@ -37,6 +37,11 @@ const TabsContainer = styled.div`
37
37
  margin: 0 auto 15px auto;
38
38
  border-bottom: 2px solid rgba(255, 255, 255, 0.1);
39
39
  padding-bottom: 10px;
40
+ overflow-x: auto;
41
+ scrollbar-width: none;
42
+ &::-webkit-scrollbar {
43
+ display: none;
44
+ }
40
45
  `;
41
46
 
42
47
  const TabButton = styled.button<{ $active: boolean }>`
@@ -299,7 +299,7 @@ const mockPacks: IItemPack[] = [
299
299
 
300
300
  ];
301
301
 
302
- // Create the story with the static mock data
302
+ // Create the story with the static mock data — all tabs enabled so layout breaks are visible
303
303
  export const Default: Story = {
304
304
  render: () => (
305
305
  <Store
@@ -310,6 +310,11 @@ export const Default: Story = {
310
310
  console.log('Purchase details:', purchase);
311
311
  return Promise.resolve(true);
312
312
  }}
313
+ customCharactersContent={
314
+ <div style={{ padding: '1rem', color: '#fff', fontFamily: "'Press Start 2P', cursive", fontSize: '0.6rem', textAlign: 'center', marginTop: '2rem' }}>
315
+ Character trading content (consumer-provided)
316
+ </div>
317
+ }
313
318
  customWalletContent={<DCWalletContent
314
319
  dcBalance={150000000} // 150M
315
320
  historyData={{ transactions: [], totalPages: 1, currentPage: 1 }}
@@ -328,11 +333,14 @@ export const Default: Story = {
328
333
  loading={false}
329
334
  onRequestHistory={() => {}}
330
335
  />}
336
+ onRedeem={async (code: string) => {
337
+ if (code === 'CHB-550-ABCDEF1234') return { success: true, dcAmount: 550 };
338
+ return { success: false, error: 'Invalid voucher code.' };
339
+ }}
331
340
  onClose={() => console.log('Store closed')}
332
341
  atlasJSON={itemsAtlasJSON}
333
342
  atlasIMG={itemsAtlasIMG}
334
- hidePremiumTab={true}
335
- tabOrder={['items', 'packs']}
343
+ tabOrder={['premium', 'packs', 'items']}
336
344
  defaultActiveTab="packs"
337
345
  textInputItemKeys={['original-greater-life-potion-2', 'original-angelic-sword-1', 'character-name-change']}
338
346
  packsBadge="SAVE"
@@ -653,6 +661,38 @@ export const INR: Story = {
653
661
  ),
654
662
  };
655
663
 
664
+ export const WithCharTradeTab: Story = {
665
+ render: () => (
666
+ <Store
667
+ items={allStoreItems}
668
+ packs={mockPacks}
669
+ userAccountType={UserAccountTypes.Free}
670
+ onPurchase={(purchase: Partial<IPurchase>) => {
671
+ console.log('Purchase details:', purchase);
672
+ return Promise.resolve(true);
673
+ }}
674
+ customCharactersContent={
675
+ <div style={{ padding: '1rem', color: '#fff', fontFamily: "'Press Start 2P', cursive", fontSize: '0.6rem', textAlign: 'center', marginTop: '2rem' }}>
676
+ Character trading content goes here (provided by consumer)
677
+ </div>
678
+ }
679
+ onClose={() => console.log('Store closed')}
680
+ atlasJSON={itemsAtlasJSON}
681
+ atlasIMG={itemsAtlasIMG}
682
+ hidePremiumTab={true}
683
+ tabOrder={['items', 'packs']}
684
+ defaultActiveTab="characters"
685
+ onTabChange={(tab, count) => console.log('[tracking] tab_change', { tab, count })}
686
+ onCartOpen={() => console.log('[tracking] cart_opened')}
687
+ onAddToCart={(item, qty) => console.log('[tracking] add_to_cart', { key: item.key, qty })}
688
+ onRemoveFromCart={(key) => console.log('[tracking] remove_from_cart', { key })}
689
+ onCheckoutStart={(items, total) => console.log('[tracking] checkout_start', { items, total })}
690
+ onPurchaseSuccess={(items, total) => console.log('[tracking] purchase_success', { items, total })}
691
+ onPurchaseError={(error) => console.log('[tracking] purchase_error', { error })}
692
+ />
693
+ ),
694
+ };
695
+
656
696
  export const WithRedeemTab: Story = {
657
697
  render: () => (
658
698
  <Store