@m3000/market 0.0.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 (154) hide show
  1. package/LICENSE +21 -0
  2. package/dist/components/blocks/auction/Auction.d.ts +49 -0
  3. package/dist/components/blocks/auction/Auction.js +44 -0
  4. package/dist/components/blocks/auction/AuctionBidForm.d.ts +11 -0
  5. package/dist/components/blocks/auction/AuctionBidForm.js +88 -0
  6. package/dist/components/blocks/auction/AuctionBidInput.d.ts +9 -0
  7. package/dist/components/blocks/auction/AuctionBidInput.js +99 -0
  8. package/dist/components/blocks/auction/AuctionContext.d.ts +71 -0
  9. package/dist/components/blocks/auction/AuctionContext.js +228 -0
  10. package/dist/components/blocks/auction/AuctionInfo.d.ts +9 -0
  11. package/dist/components/blocks/auction/AuctionInfo.js +37 -0
  12. package/dist/components/blocks/auction/AuctionLayout.d.ts +63 -0
  13. package/dist/components/blocks/auction/AuctionLayout.js +80 -0
  14. package/dist/components/blocks/auction/AuctionRankings.d.ts +16 -0
  15. package/dist/components/blocks/auction/AuctionRankings.js +334 -0
  16. package/dist/components/blocks/auction/AuctionStatusTag.d.ts +15 -0
  17. package/dist/components/blocks/auction/AuctionStatusTag.js +60 -0
  18. package/dist/components/blocks/auction/AuctionSuggestedBids.d.ts +38 -0
  19. package/dist/components/blocks/auction/AuctionSuggestedBids.js +116 -0
  20. package/dist/components/blocks/auction/AuctionYourBidCard.d.ts +27 -0
  21. package/dist/components/blocks/auction/AuctionYourBidCard.js +94 -0
  22. package/dist/components/blocks/auction/AuctionYourBids.d.ts +9 -0
  23. package/dist/components/blocks/auction/AuctionYourBids.js +49 -0
  24. package/dist/components/blocks/auction/index.d.ts +12 -0
  25. package/dist/components/blocks/index.d.ts +12 -0
  26. package/dist/components/index.d.ts +28 -0
  27. package/dist/components/primitives/Button.d.ts +31 -0
  28. package/dist/components/primitives/Button.js +117 -0
  29. package/dist/components/primitives/Drawer.d.ts +43 -0
  30. package/dist/components/primitives/Drawer.js +51 -0
  31. package/dist/components/primitives/Feedback.d.ts +28 -0
  32. package/dist/components/primitives/Feedback.js +147 -0
  33. package/dist/components/primitives/MorphDialog.d.ts +39 -0
  34. package/dist/components/primitives/MorphDialog.js +87 -0
  35. package/dist/components/primitives/Price.d.ts +84 -0
  36. package/dist/components/primitives/Price.js +255 -0
  37. package/dist/components/primitives/PriceInput.d.ts +33 -0
  38. package/dist/components/primitives/PriceInput.js +25 -0
  39. package/dist/components/primitives/Receipt.d.ts +164 -0
  40. package/dist/components/primitives/Receipt.js +344 -0
  41. package/dist/components/primitives/Scale.d.ts +67 -0
  42. package/dist/components/primitives/Scale.js +132 -0
  43. package/dist/components/primitives/Separator.d.ts +22 -0
  44. package/dist/components/primitives/Separator.js +62 -0
  45. package/dist/components/primitives/Skeleton.d.ts +14 -0
  46. package/dist/components/primitives/Skeleton.js +20 -0
  47. package/dist/components/primitives/SteppedInput.d.ts +94 -0
  48. package/dist/components/primitives/SteppedInput.js +154 -0
  49. package/dist/components/primitives/Tabs.d.ts +37 -0
  50. package/dist/components/primitives/Tabs.js +99 -0
  51. package/dist/components/primitives/Tag.d.ts +24 -0
  52. package/dist/components/primitives/Tag.js +22 -0
  53. package/dist/components/primitives/Text.d.ts +32 -0
  54. package/dist/components/primitives/Text.js +65 -0
  55. package/dist/components/primitives/countdown/Countdown.d.ts +24 -0
  56. package/dist/components/primitives/countdown/Countdown.js +22 -0
  57. package/dist/components/primitives/framed-image/FramedImage.d.ts +13 -0
  58. package/dist/components/primitives/framed-image/FramedImage.js +37 -0
  59. package/dist/components/primitives/index.d.ts +17 -0
  60. package/dist/components/primitives/ranked-list/Ranking.d.ts +117 -0
  61. package/dist/components/primitives/ranked-list/Ranking.js +219 -0
  62. package/dist/components/primitives/ranked-list/index.d.ts +1 -0
  63. package/dist/hooks/useCountdown.d.ts +20 -0
  64. package/dist/hooks/useCountdown.js +75 -0
  65. package/dist/index.d.ts +36 -0
  66. package/dist/index.js +36 -0
  67. package/dist/lib/cn.d.ts +6 -0
  68. package/dist/lib/cn.js +75 -0
  69. package/dist/lib/motion.d.ts +19 -0
  70. package/dist/lib/motion.js +43 -0
  71. package/dist/types/index.d.ts +120 -0
  72. package/dist/utils/format.d.ts +38 -0
  73. package/dist/utils/format.js +103 -0
  74. package/dist/utils/rank-utils.d.ts +34 -0
  75. package/dist/utils/rank-utils.js +80 -0
  76. package/dist/utils/tick-validation.d.ts +22 -0
  77. package/dist/utils/tick-validation.js +40 -0
  78. package/package.json +92 -0
  79. package/src/components/blocks/auction/Auction.tsx +74 -0
  80. package/src/components/blocks/auction/AuctionArtwork.tsx +4 -0
  81. package/src/components/blocks/auction/AuctionBidForm.tsx +138 -0
  82. package/src/components/blocks/auction/AuctionBidInput.tsx +166 -0
  83. package/src/components/blocks/auction/AuctionContext.tsx +401 -0
  84. package/src/components/blocks/auction/AuctionInfo.tsx +36 -0
  85. package/src/components/blocks/auction/AuctionLayout.tsx +200 -0
  86. package/src/components/blocks/auction/AuctionRankings.tsx +435 -0
  87. package/src/components/blocks/auction/AuctionStatusTag.tsx +98 -0
  88. package/src/components/blocks/auction/AuctionSuggestedBids.tsx +203 -0
  89. package/src/components/blocks/auction/AuctionYourBidCard.tsx +125 -0
  90. package/src/components/blocks/auction/AuctionYourBids.tsx +61 -0
  91. package/src/components/blocks/auction/index.ts +42 -0
  92. package/src/components/blocks/index.ts +1 -0
  93. package/src/components/index.ts +2 -0
  94. package/src/components/primitives/Button.tsx +183 -0
  95. package/src/components/primitives/Drawer.tsx +125 -0
  96. package/src/components/primitives/Feedback.tsx +185 -0
  97. package/src/components/primitives/MorphDialog.tsx +160 -0
  98. package/src/components/primitives/Price.tsx +394 -0
  99. package/src/components/primitives/PriceInput.tsx +48 -0
  100. package/src/components/primitives/Receipt.tsx +711 -0
  101. package/src/components/primitives/Scale.tsx +287 -0
  102. package/src/components/primitives/Separator.tsx +87 -0
  103. package/src/components/primitives/Skeleton.tsx +33 -0
  104. package/src/components/primitives/SteppedInput.tsx +313 -0
  105. package/src/components/primitives/Tabs.tsx +161 -0
  106. package/src/components/primitives/Tag.tsx +48 -0
  107. package/src/components/primitives/Text.tsx +102 -0
  108. package/src/components/primitives/countdown/Countdown.tsx +43 -0
  109. package/src/components/primitives/countdown/index.ts +2 -0
  110. package/src/components/primitives/framed-image/FramedImage.tsx +51 -0
  111. package/src/components/primitives/framed-image/index.ts +1 -0
  112. package/src/components/primitives/index.ts +42 -0
  113. package/src/components/primitives/ranked-list/RankedList.tsx +9 -0
  114. package/src/components/primitives/ranked-list/Ranking.tsx +454 -0
  115. package/src/components/primitives/ranked-list/index.ts +8 -0
  116. package/src/hooks/index.ts +1 -0
  117. package/src/hooks/useCountdown.ts +91 -0
  118. package/src/index.ts +130 -0
  119. package/src/lib/cn.ts +81 -0
  120. package/src/lib/index.ts +2 -0
  121. package/src/lib/motion.ts +55 -0
  122. package/src/public/lea-83-time-walk.png +0 -0
  123. package/src/public/lea-83-time-walk.webp +0 -0
  124. package/src/stories/Auction.stories.tsx +658 -0
  125. package/src/stories/AuctionLayout.stories.tsx +313 -0
  126. package/src/stories/AuctionStatusTag.stories.tsx +166 -0
  127. package/src/stories/AuctionYourBidCard.stories.tsx +257 -0
  128. package/src/stories/Button.stories.tsx +306 -0
  129. package/src/stories/Countdown.stories.tsx +158 -0
  130. package/src/stories/Feedback.stories.tsx +80 -0
  131. package/src/stories/FramedImage.stories.tsx +46 -0
  132. package/src/stories/MorphDialog.stories.tsx +88 -0
  133. package/src/stories/Price.stories.tsx +292 -0
  134. package/src/stories/RankedList.stories.tsx +190 -0
  135. package/src/stories/Receipt.stories.tsx +221 -0
  136. package/src/stories/Scale.stories.tsx +578 -0
  137. package/src/stories/Separator.stories.tsx +188 -0
  138. package/src/stories/Skeleton.stories.tsx +138 -0
  139. package/src/stories/SteppedInput.stories.tsx +321 -0
  140. package/src/stories/Tabs.stories.tsx +215 -0
  141. package/src/stories/Tag.stories.tsx +138 -0
  142. package/src/stories/Text.stories.tsx +245 -0
  143. package/src/styles/globals.css +39 -0
  144. package/src/styles/index.css +4 -0
  145. package/src/styles/theme/animation.css +11 -0
  146. package/src/styles/theme/color.css +185 -0
  147. package/src/styles/theme/index.css +3 -0
  148. package/src/styles/theme/typography.css +3 -0
  149. package/src/styles/utility.css +8 -0
  150. package/src/types/index.ts +149 -0
  151. package/src/utils/format.ts +130 -0
  152. package/src/utils/index.ts +16 -0
  153. package/src/utils/rank-utils.ts +131 -0
  154. package/src/utils/tick-validation.ts +65 -0
@@ -0,0 +1,74 @@
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+ import type {
5
+ AuctionData,
6
+ AuctionFormatters,
7
+ AuctionUserBid,
8
+ RankableBid,
9
+ } from "@/types";
10
+ import { AuctionProvider } from "./AuctionContext";
11
+
12
+ export interface AuctionProps {
13
+ auction: AuctionData;
14
+ bids: RankableBid[];
15
+ userBids: AuctionUserBid[];
16
+ onPlaceBid: (price: bigint, quantity: bigint) => Promise<boolean>;
17
+ onTopUpBid: (
18
+ bidId: bigint,
19
+ newPrice: bigint,
20
+ additionalValue: bigint,
21
+ ) => Promise<boolean>;
22
+ onClaimEdition?: (bidId: string) => Promise<boolean>;
23
+ formatters?: AuctionFormatters;
24
+ children: ReactNode;
25
+ className?: string;
26
+ }
27
+
28
+ /**
29
+ * Root component for an auction interface.
30
+ * Provides context and orchestrates the layout of child components.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <Auction
35
+ * auction={auctionData}
36
+ * bids={bids}
37
+ * userBids={myBids}
38
+ * onPlaceBid={async (price, qty) => { /* wagmi call *\/ }}
39
+ * onTopUpBid={async (bidId, newPrice, value) => { /* wagmi call *\/ }}
40
+ * >
41
+ * <AuctionInfo />
42
+ * <AuctionBidInput />
43
+ * <AuctionRankings />
44
+ * <AuctionYourBids />
45
+ * </Auction>
46
+ * ```
47
+ */
48
+ export function Auction({
49
+ auction,
50
+ bids,
51
+ userBids,
52
+ onPlaceBid,
53
+ onTopUpBid,
54
+ onClaimEdition,
55
+ formatters,
56
+ children,
57
+ className,
58
+ }: AuctionProps): React.ReactElement {
59
+ return (
60
+ <AuctionProvider
61
+ auction={auction}
62
+ bids={bids}
63
+ userBids={userBids}
64
+ onPlaceBid={onPlaceBid}
65
+ onTopUpBid={onTopUpBid}
66
+ onClaimEdition={onClaimEdition}
67
+ formatters={formatters}
68
+ >
69
+ <div className={className}>{children}</div>
70
+ </AuctionProvider>
71
+ );
72
+ }
73
+
74
+ export { useAuctionContext } from "./AuctionContext";
@@ -0,0 +1,4 @@
1
+ export {
2
+ FramedImage as AuctionArtwork,
3
+ type FramedImageProps as AuctionArtworkProps,
4
+ } from "@/components/primitives/framed-image";
@@ -0,0 +1,138 @@
1
+ "use client";
2
+
3
+ import { Button, SteppedInput, Text } from "@/components/primitives";
4
+ import { cn } from "@/lib";
5
+ import { CursorGrowIcon } from "../../primitives/SteppedInput";
6
+ import { useAuctionContext } from "./AuctionContext";
7
+
8
+ export function AuctionBidFormRoot({
9
+ className,
10
+ }: {
11
+ className?: string;
12
+ }): React.ReactElement {
13
+ const {
14
+ isAuctionEnded,
15
+ minBidValue,
16
+ tickConfig,
17
+ tickSize,
18
+ lockedBid,
19
+ placeBidOperation,
20
+ topUpOperation,
21
+ handlePlaceBid,
22
+ handleTopUp,
23
+ bidValue,
24
+ setBidValue,
25
+ formatPrice,
26
+ currencySymbol,
27
+ inputDecimals,
28
+ cancelBidding,
29
+ } = useAuctionContext();
30
+
31
+ const effectiveMinBid =
32
+ lockedBid !== null && lockedBid.priceValue > minBidValue
33
+ ? lockedBid.priceValue
34
+ : minBidValue;
35
+
36
+ const getTickSize = (currentValue: bigint) => {
37
+ if (!tickConfig) return tickSize;
38
+ return currentValue > tickConfig.threshold
39
+ ? tickConfig.largeTickSize
40
+ : tickConfig.smallTickSize;
41
+ };
42
+
43
+ const activeOperation =
44
+ lockedBid !== null ? topUpOperation : placeBidOperation;
45
+ const status = activeOperation.status;
46
+ const errorMessage = activeOperation.error;
47
+
48
+ const handleSubmit = async () => {
49
+ const success =
50
+ lockedBid !== null
51
+ ? await handleTopUp(bidValue.toString())
52
+ : await handlePlaceBid(bidValue.toString());
53
+ if (success) setBidValue(effectiveMinBid);
54
+ };
55
+
56
+ const isLoading =
57
+ status === "pending" || status === "confirming" || status === "indexing";
58
+
59
+ return (
60
+ <div className={cn("flex flex-col gap-4", className)}>
61
+ {status === "error" ? (
62
+ <div className="rounded-xs bg-destructive-muted p-2 text-destructive">
63
+ <Text size="1">{errorMessage}</Text>
64
+ </div>
65
+ ) : null}
66
+ <fieldset
67
+ disabled={isAuctionEnded}
68
+ className="flex w-full flex-col gap-4"
69
+ >
70
+ {lockedBid !== null ? (
71
+ <Text size="1">
72
+ Update your bid. You will pay the difference between the new bid
73
+ amount and the existing bid.
74
+ </Text>
75
+ ) : (
76
+ <Text size="1">Place a new bid to participate in the auction.</Text>
77
+ )}
78
+ <SteppedInput.Root
79
+ value={bidValue}
80
+ onChange={setBidValue}
81
+ min={effectiveMinBid}
82
+ getTickSize={getTickSize}
83
+ decimals={inputDecimals}
84
+ disabled={isAuctionEnded}
85
+ snapToTick="nearest"
86
+ >
87
+ <SteppedInput.Group>
88
+ <SteppedInput.Decrement />
89
+ <SteppedInput.ScrubArea>
90
+ <SteppedInput.ScrubAreaCursor>
91
+ <CursorGrowIcon />
92
+ </SteppedInput.ScrubAreaCursor>
93
+ <SteppedInput.Value>
94
+ {({ value }) => `${formatPrice(value)} ${currencySymbol}`}
95
+ </SteppedInput.Value>
96
+ </SteppedInput.ScrubArea>
97
+ <SteppedInput.Increment />
98
+ </SteppedInput.Group>
99
+ </SteppedInput.Root>
100
+ <div className="flex w-full gap-2">
101
+ <Button
102
+ type="button"
103
+ color="tertiary"
104
+ className="grow whitespace-nowrap"
105
+ onClick={cancelBidding}
106
+ >
107
+ Cancel
108
+ </Button>
109
+ <Button
110
+ className="grow"
111
+ type="button"
112
+ loading={isLoading}
113
+ disabled={
114
+ isAuctionEnded ||
115
+ (!!lockedBid && bidValue - lockedBid.priceValue === 0n)
116
+ }
117
+ onClick={handleSubmit}
118
+ >
119
+ {lockedBid !== null ? (
120
+ <span>
121
+ Update bid (+{formatPrice(bidValue - lockedBid.priceValue)}{" "}
122
+ {currencySymbol})
123
+ </span>
124
+ ) : (
125
+ <span>Place bid</span>
126
+ )}
127
+ </Button>
128
+ </div>
129
+ </fieldset>
130
+ </div>
131
+ );
132
+ }
133
+
134
+ export const AuctionBidForm: {
135
+ Root: typeof AuctionBidFormRoot;
136
+ } = {
137
+ Root: AuctionBidFormRoot,
138
+ };
@@ -0,0 +1,166 @@
1
+ "use client";
2
+
3
+ import { AnimatePresence, motion } from "motion/react";
4
+ import { useCallback, useEffect } from "react";
5
+ import { Button, SteppedInput, Text } from "@/components/primitives";
6
+ import { transitions } from "@/lib";
7
+ import { CursorGrowIcon } from "../../primitives/SteppedInput";
8
+ import { useAuctionContext } from "./AuctionContext";
9
+
10
+ export interface AuctionBidInputProps {
11
+ className?: string;
12
+ }
13
+
14
+ export function AuctionBidInput({
15
+ className,
16
+ }: AuctionBidInputProps): React.ReactElement {
17
+ const {
18
+ isAuctionEnded,
19
+ minBidValue,
20
+ tickConfig,
21
+ tickSize,
22
+ lockedBid,
23
+ setLockedBid,
24
+ placeBidOperation,
25
+ topUpOperation,
26
+ handlePlaceBid,
27
+ handleTopUp,
28
+ getProjectedRank,
29
+ bidValue,
30
+ setBidValue,
31
+ formatPrice,
32
+ currencySymbol,
33
+ inputDecimals,
34
+ } = useAuctionContext();
35
+
36
+ const effectiveMinBid =
37
+ lockedBid !== null && lockedBid.priceValue > minBidValue
38
+ ? lockedBid.priceValue
39
+ : minBidValue;
40
+
41
+ useEffect(() => {
42
+ setBidValue((prev) => (prev < effectiveMinBid ? effectiveMinBid : prev));
43
+ }, [effectiveMinBid, setBidValue]);
44
+
45
+ const getTickSize = useCallback(
46
+ (currentValue: bigint) => {
47
+ if (!tickConfig) return tickSize;
48
+ return currentValue > tickConfig.threshold
49
+ ? tickConfig.largeTickSize
50
+ : tickConfig.smallTickSize;
51
+ },
52
+ [tickConfig, tickSize],
53
+ );
54
+
55
+ const activeOperation =
56
+ lockedBid !== null ? topUpOperation : placeBidOperation;
57
+ const status = activeOperation.status;
58
+ const errorMessage = activeOperation.error;
59
+
60
+ const { rank: projectedRank, isWinning: isProjectedWinning } =
61
+ getProjectedRank(bidValue);
62
+
63
+ const bidDisplay = `${formatPrice(bidValue)} ${currencySymbol}`;
64
+
65
+ const primaryCtaLabel =
66
+ lockedBid !== null
67
+ ? projectedRank != null && !isAuctionEnded
68
+ ? `Top up to rank #${projectedRank}${
69
+ !isProjectedWinning ? " (outside winning range)" : ""
70
+ }`
71
+ : "Top up"
72
+ : projectedRank != null && !isAuctionEnded
73
+ ? `Bid ${bidDisplay} and get rank #${projectedRank}${
74
+ !isProjectedWinning ? " (outside winning range)" : ""
75
+ }`
76
+ : `Bid ${bidDisplay}`;
77
+
78
+ const handleSubmit = useCallback(async () => {
79
+ const success =
80
+ lockedBid !== null
81
+ ? await handleTopUp(bidValue.toString())
82
+ : await handlePlaceBid(bidValue.toString());
83
+ if (success) setBidValue(effectiveMinBid);
84
+ }, [
85
+ bidValue,
86
+ effectiveMinBid,
87
+ lockedBid,
88
+ handlePlaceBid,
89
+ handleTopUp,
90
+ setBidValue,
91
+ ]);
92
+
93
+ const isLoading =
94
+ status === "pending" || status === "confirming" || status === "indexing";
95
+
96
+ return (
97
+ <div className={className}>
98
+ {status === "error" ? (
99
+ <div className="bg-error/10 text-error mb-2 rounded-xs p-2">
100
+ <Text size="1">{errorMessage}</Text>
101
+ </div>
102
+ ) : null}
103
+ <fieldset
104
+ disabled={isAuctionEnded}
105
+ className="flex w-full flex-col gap-2"
106
+ >
107
+ <SteppedInput.Root
108
+ value={bidValue}
109
+ onChange={setBidValue}
110
+ min={effectiveMinBid}
111
+ getTickSize={getTickSize}
112
+ decimals={inputDecimals}
113
+ disabled={isAuctionEnded}
114
+ snapToTick="nearest"
115
+ >
116
+ <SteppedInput.Group>
117
+ <SteppedInput.Decrement />
118
+ <SteppedInput.ScrubArea>
119
+ <SteppedInput.ScrubAreaCursor>
120
+ <CursorGrowIcon />
121
+ </SteppedInput.ScrubAreaCursor>
122
+ <SteppedInput.Value>
123
+ {({ value }) => `${formatPrice(value)} ${currencySymbol}`}
124
+ </SteppedInput.Value>
125
+ </SteppedInput.ScrubArea>
126
+ <SteppedInput.Increment />
127
+ </SteppedInput.Group>
128
+ </SteppedInput.Root>
129
+ <div className="flex flex-row gap-2">
130
+ <AnimatePresence mode="popLayout">
131
+ {lockedBid !== null && (
132
+ <motion.div
133
+ key="cancel-button"
134
+ initial={{ opacity: 0 }}
135
+ animate={{ opacity: 1 }}
136
+ exit={{ opacity: 0 }}
137
+ transition={transitions.fade}
138
+ className="flex-1"
139
+ >
140
+ <Button
141
+ type="button"
142
+ color="tertiary"
143
+ className="w-full whitespace-nowrap"
144
+ onClick={() => setLockedBid(null)}
145
+ >
146
+ Cancel top up
147
+ </Button>
148
+ </motion.div>
149
+ )}
150
+ </AnimatePresence>
151
+ <div className="min-w-0 flex-1">
152
+ <Button
153
+ type="button"
154
+ loading={isLoading}
155
+ disabled={isAuctionEnded}
156
+ onClick={handleSubmit}
157
+ className="w-full whitespace-nowrap"
158
+ >
159
+ {primaryCtaLabel}
160
+ </Button>
161
+ </div>
162
+ </div>
163
+ </fieldset>
164
+ </div>
165
+ );
166
+ }