@anker-in/lib 1.0.0-beta.5 → 1.0.0-beta.6
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 +41 -8
- package/.gitkeep +0 -0
- package/.turbo/turbo-build.log +0 -27
- package/.turbo/turbo-test.log +0 -14
- package/USAGE_EXAMPLE.md +0 -425
- package/jest.config.ts +0 -12
- package/src/__tests__/math.test.ts +0 -15
- package/src/index.ts +0 -7
- package/src/math.ts +0 -5
- package/tsconfig.json +0 -20
- package/tsup.config.ts +0 -20
package/package.json
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anker-in/lib",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.6",
|
|
4
|
+
"description": "Convenience package that re-exports all Anker headless packages",
|
|
4
5
|
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
5
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"default": "./dist/index.mjs"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
6
23
|
"dependencies": {
|
|
7
|
-
"@anker-in/
|
|
8
|
-
"@anker-in/
|
|
9
|
-
"@anker-in/
|
|
24
|
+
"@anker-in/shared": "1.0.0-beta.2",
|
|
25
|
+
"@anker-in/shopify": "0.0.0-beta.6",
|
|
26
|
+
"@anker-in/cart": "1.0.0-beta.2"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": "^18.0.0",
|
|
30
|
+
"react-dom": "^18.0.0"
|
|
10
31
|
},
|
|
11
32
|
"devDependencies": {
|
|
12
33
|
"@types/jest": "^29.5.12",
|
|
@@ -14,12 +35,24 @@
|
|
|
14
35
|
"jest": "^29.0.0",
|
|
15
36
|
"ts-jest": "^29.2.6",
|
|
16
37
|
"tsup": "^8.4.0",
|
|
17
|
-
"typescript": "^5.0.0"
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"@anker-in/shared": "1.0.0-beta.2",
|
|
40
|
+
"@anker-in/shopify": "0.0.0-beta.6",
|
|
41
|
+
"@anker-in/cart": "1.0.0-beta.2"
|
|
18
42
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"registry": "https://registry.npmjs.org/"
|
|
22
46
|
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"anker",
|
|
49
|
+
"headless",
|
|
50
|
+
"shopify",
|
|
51
|
+
"ecommerce",
|
|
52
|
+
"react"
|
|
53
|
+
],
|
|
54
|
+
"author": "Anker",
|
|
55
|
+
"license": "MIT",
|
|
23
56
|
"scripts": {
|
|
24
57
|
"dev": "tsup --watch",
|
|
25
58
|
"build": "tsup",
|
package/.gitkeep
DELETED
|
File without changes
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @anker-in/lib@1.0.0 build /Users/anker/Code/headless-ui/packages/lib
|
|
3
|
-
> tsup
|
|
4
|
-
|
|
5
|
-
CLI Building entry: src/index.ts
|
|
6
|
-
CLI Using tsconfig: tsconfig.json
|
|
7
|
-
CLI tsup v8.4.0
|
|
8
|
-
CLI Using tsup config: /Users/anker/Code/headless-ui/packages/lib/tsup.config.ts
|
|
9
|
-
CLI Target: esnext
|
|
10
|
-
CLI Cleaning output folder
|
|
11
|
-
ESM Build start
|
|
12
|
-
CJS Build start
|
|
13
|
-
IIFE Build start
|
|
14
|
-
If you do not supply "output.name", you may not be able to access the exports of an IIFE bundle.
|
|
15
|
-
IIFE dist/index.global.js 198.00 B
|
|
16
|
-
IIFE dist/index.global.js.map 397.00 B
|
|
17
|
-
IIFE ⚡️ Build success in 436ms
|
|
18
|
-
CJS dist/index.js 143.00 B
|
|
19
|
-
CJS dist/index.js.map 389.00 B
|
|
20
|
-
CJS ⚡️ Build success in 438ms
|
|
21
|
-
ESM dist/index.mjs 130.00 B
|
|
22
|
-
ESM dist/index.mjs.map 390.00 B
|
|
23
|
-
ESM ⚡️ Build success in 438ms
|
|
24
|
-
DTS Build start
|
|
25
|
-
DTS ⚡️ Build success in 4317ms
|
|
26
|
-
DTS dist/index.d.mts 161.00 B
|
|
27
|
-
DTS dist/index.d.ts 161.00 B
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @anker-in/lib@1.0.0 test /Users/anker/Code/headless-ui/packages/lib
|
|
3
|
-
> jest --passWithNoTests
|
|
4
|
-
|
|
5
|
-
PASS src/__tests__/math.test.ts
|
|
6
|
-
math functions
|
|
7
|
-
✓ add should correctly add two numbers (1 ms)
|
|
8
|
-
✓ subtract should correctly subtract two numbers
|
|
9
|
-
|
|
10
|
-
Test Suites: 1 passed, 1 total
|
|
11
|
-
Tests: 2 passed, 2 total
|
|
12
|
-
Snapshots: 0 total
|
|
13
|
-
Time: 1.197 s
|
|
14
|
-
Ran all test suites.
|
package/USAGE_EXAMPLE.md
DELETED
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
# 使用示例
|
|
2
|
-
|
|
3
|
-
## 完整的电商应用示例
|
|
4
|
-
|
|
5
|
-
以下是一个完整的示例,展示如何使用 `@anker-in/lib` 构建电商应用:
|
|
6
|
-
|
|
7
|
-
### 1. 应用入口(App.tsx)
|
|
8
|
-
|
|
9
|
-
```tsx
|
|
10
|
-
import { HeadlessProvider } from '@anker-in/lib'
|
|
11
|
-
import { ProductList } from './components/ProductList'
|
|
12
|
-
import { Cart } from './components/Cart'
|
|
13
|
-
|
|
14
|
-
const headlessConfig = {
|
|
15
|
-
storefrontToken: process.env.NEXT_PUBLIC_SHOPIFY_TOKEN!,
|
|
16
|
-
storeDomain: process.env.NEXT_PUBLIC_SHOPIFY_DOMAIN!,
|
|
17
|
-
locale: 'zh-CN',
|
|
18
|
-
comboMetafieldsNamespace: 'custom',
|
|
19
|
-
cartIdCookieName: 'anker_cart_id',
|
|
20
|
-
brand: 'Anker',
|
|
21
|
-
appName: 'Anker Store'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default function App() {
|
|
25
|
-
return (
|
|
26
|
-
<HeadlessProvider headlessConfig={headlessConfig}>
|
|
27
|
-
<div className="app">
|
|
28
|
-
<header>
|
|
29
|
-
<h1>Anker 商店</h1>
|
|
30
|
-
<Cart />
|
|
31
|
-
</header>
|
|
32
|
-
<main>
|
|
33
|
-
<ProductList />
|
|
34
|
-
</main>
|
|
35
|
-
</div>
|
|
36
|
-
</HeadlessProvider>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 2. 产品列表(ProductList.tsx)
|
|
42
|
-
|
|
43
|
-
```tsx
|
|
44
|
-
import { useProducts, useHeadlessContext } from '@anker-in/lib'
|
|
45
|
-
import { ProductCard } from './ProductCard'
|
|
46
|
-
|
|
47
|
-
export function ProductList() {
|
|
48
|
-
const { locale } = useHeadlessContext()
|
|
49
|
-
const { data: products, isLoading } = useProducts({
|
|
50
|
-
first: 12,
|
|
51
|
-
// 其他查询参数...
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
if (isLoading) return <div>加载中...</div>
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<div className="product-grid">
|
|
58
|
-
{products?.map(product => (
|
|
59
|
-
<ProductCard key={product.id} product={product} />
|
|
60
|
-
))}
|
|
61
|
-
</div>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### 3. 产品卡片(ProductCard.tsx)
|
|
67
|
-
|
|
68
|
-
```tsx
|
|
69
|
-
import {
|
|
70
|
-
useAddToCart,
|
|
71
|
-
useBuyNow,
|
|
72
|
-
type Product
|
|
73
|
-
} from '@anker-in/lib'
|
|
74
|
-
|
|
75
|
-
interface ProductCardProps {
|
|
76
|
-
product: Product
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function ProductCard({ product }: ProductCardProps) {
|
|
80
|
-
const { trigger: addToCart, isMutating: isAdding } = useAddToCart()
|
|
81
|
-
const { trigger: buyNow, isMutating: isBuying } = useBuyNow()
|
|
82
|
-
|
|
83
|
-
const handleAddToCart = async () => {
|
|
84
|
-
try {
|
|
85
|
-
await addToCart({
|
|
86
|
-
lineItems: [{
|
|
87
|
-
variant: { id: product.variants[0].id },
|
|
88
|
-
quantity: 1
|
|
89
|
-
}]
|
|
90
|
-
})
|
|
91
|
-
alert('已添加到购物车!')
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error('添加失败:', error)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const handleBuyNow = async () => {
|
|
98
|
-
await buyNow({
|
|
99
|
-
lineItems: [{
|
|
100
|
-
variant: { id: product.variants[0].id },
|
|
101
|
-
quantity: 1
|
|
102
|
-
}],
|
|
103
|
-
gtmParams: {
|
|
104
|
-
currency: 'USD',
|
|
105
|
-
value: parseFloat(product.variants[0].price.amount)
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
<div className="product-card">
|
|
112
|
-
<img src={product.images[0]?.url} alt={product.title} />
|
|
113
|
-
<h3>{product.title}</h3>
|
|
114
|
-
<p className="price">${product.variants[0].price.amount}</p>
|
|
115
|
-
|
|
116
|
-
<div className="actions">
|
|
117
|
-
<button
|
|
118
|
-
onClick={handleAddToCart}
|
|
119
|
-
disabled={isAdding}
|
|
120
|
-
>
|
|
121
|
-
{isAdding ? '添加中...' : '加入购物车'}
|
|
122
|
-
</button>
|
|
123
|
-
|
|
124
|
-
<button
|
|
125
|
-
onClick={handleBuyNow}
|
|
126
|
-
disabled={isBuying}
|
|
127
|
-
className="primary"
|
|
128
|
-
>
|
|
129
|
-
{isBuying ? '处理中...' : '立即购买'}
|
|
130
|
-
</button>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 4. 购物车(Cart.tsx)
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
import {
|
|
141
|
-
useCart,
|
|
142
|
-
useUpdateCartLines,
|
|
143
|
-
useRemoveCartLines,
|
|
144
|
-
useApplyCartCodes
|
|
145
|
-
} from '@anker-in/lib'
|
|
146
|
-
import { useState } from 'react'
|
|
147
|
-
|
|
148
|
-
export function Cart() {
|
|
149
|
-
const { data: cart } = useCart()
|
|
150
|
-
const { trigger: updateLines } = useUpdateCartLines()
|
|
151
|
-
const { trigger: removeLines } = useRemoveCartLines()
|
|
152
|
-
const { trigger: applyCode } = useApplyCartCodes()
|
|
153
|
-
const [discountCode, setDiscountCode] = useState('')
|
|
154
|
-
|
|
155
|
-
const handleQuantityChange = (lineId: string, quantity: number) => {
|
|
156
|
-
updateLines({
|
|
157
|
-
lines: [{
|
|
158
|
-
id: lineId,
|
|
159
|
-
quantity
|
|
160
|
-
}]
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const handleRemove = (lineId: string) => {
|
|
165
|
-
removeLines({ lineIds: [lineId] })
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const handleApplyDiscount = () => {
|
|
169
|
-
if (discountCode) {
|
|
170
|
-
applyCode({ discountCodes: [discountCode] })
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!cart) return <div>购物车为空</div>
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<div className="cart">
|
|
178
|
-
<h2>购物车 ({cart.lines.length})</h2>
|
|
179
|
-
|
|
180
|
-
{cart.lines.map(line => (
|
|
181
|
-
<div key={line.id} className="cart-item">
|
|
182
|
-
<img src={line.merchandise.image?.url} alt={line.merchandise.title} />
|
|
183
|
-
<div className="info">
|
|
184
|
-
<h4>{line.merchandise.product.title}</h4>
|
|
185
|
-
<p>{line.merchandise.title}</p>
|
|
186
|
-
<p className="price">${line.cost.totalAmount.amount}</p>
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<div className="quantity">
|
|
190
|
-
<button onClick={() => handleQuantityChange(line.id, line.quantity - 1)}>
|
|
191
|
-
-
|
|
192
|
-
</button>
|
|
193
|
-
<span>{line.quantity}</span>
|
|
194
|
-
<button onClick={() => handleQuantityChange(line.id, line.quantity + 1)}>
|
|
195
|
-
+
|
|
196
|
-
</button>
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
<button onClick={() => handleRemove(line.id)}>删除</button>
|
|
200
|
-
</div>
|
|
201
|
-
))}
|
|
202
|
-
|
|
203
|
-
<div className="discount">
|
|
204
|
-
<input
|
|
205
|
-
type="text"
|
|
206
|
-
placeholder="优惠码"
|
|
207
|
-
value={discountCode}
|
|
208
|
-
onChange={(e) => setDiscountCode(e.target.value)}
|
|
209
|
-
/>
|
|
210
|
-
<button onClick={handleApplyDiscount}>应用</button>
|
|
211
|
-
</div>
|
|
212
|
-
|
|
213
|
-
<div className="total">
|
|
214
|
-
<h3>总计: ${cart.cost.totalAmount.amount}</h3>
|
|
215
|
-
<a href={cart.checkoutUrl} className="checkout-button">
|
|
216
|
-
去结账
|
|
217
|
-
</a>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
)
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### 5. 产品详情页(ProductDetail.tsx)
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
import {
|
|
228
|
-
useProduct,
|
|
229
|
-
useBuyNow,
|
|
230
|
-
useAddToCart,
|
|
231
|
-
useHeadlessContext
|
|
232
|
-
} from '@anker-in/lib'
|
|
233
|
-
import { useState } from 'react'
|
|
234
|
-
|
|
235
|
-
interface ProductDetailProps {
|
|
236
|
-
productId: string
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function ProductDetail({ productId }: ProductDetailProps) {
|
|
240
|
-
const { brand } = useHeadlessContext()
|
|
241
|
-
const { data: product, isLoading } = useProduct(productId)
|
|
242
|
-
const [selectedVariant, setSelectedVariant] = useState(0)
|
|
243
|
-
const [quantity, setQuantity] = useState(1)
|
|
244
|
-
|
|
245
|
-
const { trigger: buyNow } = useBuyNow()
|
|
246
|
-
const { trigger: addToCart } = useAddToCart()
|
|
247
|
-
|
|
248
|
-
if (isLoading) return <div>加载中...</div>
|
|
249
|
-
if (!product) return <div>产品未找到</div>
|
|
250
|
-
|
|
251
|
-
const currentVariant = product.variants[selectedVariant]
|
|
252
|
-
|
|
253
|
-
return (
|
|
254
|
-
<div className="product-detail">
|
|
255
|
-
<div className="gallery">
|
|
256
|
-
{product.images.map((image, idx) => (
|
|
257
|
-
<img key={idx} src={image.url} alt={`${product.title} ${idx + 1}`} />
|
|
258
|
-
))}
|
|
259
|
-
</div>
|
|
260
|
-
|
|
261
|
-
<div className="info">
|
|
262
|
-
<span className="brand">{brand}</span>
|
|
263
|
-
<h1>{product.title}</h1>
|
|
264
|
-
<div dangerouslySetInnerHTML={{ __html: product.descriptionHtml }} />
|
|
265
|
-
|
|
266
|
-
<div className="variants">
|
|
267
|
-
<h3>选择规格</h3>
|
|
268
|
-
{product.variants.map((variant, idx) => (
|
|
269
|
-
<button
|
|
270
|
-
key={variant.id}
|
|
271
|
-
onClick={() => setSelectedVariant(idx)}
|
|
272
|
-
className={selectedVariant === idx ? 'active' : ''}
|
|
273
|
-
>
|
|
274
|
-
{variant.title}
|
|
275
|
-
</button>
|
|
276
|
-
))}
|
|
277
|
-
</div>
|
|
278
|
-
|
|
279
|
-
<div className="price">
|
|
280
|
-
<h2>${currentVariant.price.amount}</h2>
|
|
281
|
-
</div>
|
|
282
|
-
|
|
283
|
-
<div className="quantity">
|
|
284
|
-
<label>数量:</label>
|
|
285
|
-
<input
|
|
286
|
-
type="number"
|
|
287
|
-
min="1"
|
|
288
|
-
value={quantity}
|
|
289
|
-
onChange={(e) => setQuantity(parseInt(e.target.value))}
|
|
290
|
-
/>
|
|
291
|
-
</div>
|
|
292
|
-
|
|
293
|
-
<div className="actions">
|
|
294
|
-
<button
|
|
295
|
-
onClick={() => addToCart({
|
|
296
|
-
lineItems: [{
|
|
297
|
-
variant: { id: currentVariant.id },
|
|
298
|
-
quantity
|
|
299
|
-
}]
|
|
300
|
-
})}
|
|
301
|
-
className="add-to-cart"
|
|
302
|
-
>
|
|
303
|
-
加入购物车
|
|
304
|
-
</button>
|
|
305
|
-
|
|
306
|
-
<button
|
|
307
|
-
onClick={() => buyNow({
|
|
308
|
-
lineItems: [{
|
|
309
|
-
variant: { id: currentVariant.id },
|
|
310
|
-
quantity
|
|
311
|
-
}],
|
|
312
|
-
gtmParams: {
|
|
313
|
-
currency: 'USD',
|
|
314
|
-
value: parseFloat(currentVariant.price.amount) * quantity,
|
|
315
|
-
items: [{
|
|
316
|
-
item_id: product.id,
|
|
317
|
-
item_name: product.title,
|
|
318
|
-
price: parseFloat(currentVariant.price.amount),
|
|
319
|
-
quantity
|
|
320
|
-
}]
|
|
321
|
-
}
|
|
322
|
-
})}
|
|
323
|
-
className="buy-now"
|
|
324
|
-
>
|
|
325
|
-
立即购买
|
|
326
|
-
</button>
|
|
327
|
-
</div>
|
|
328
|
-
</div>
|
|
329
|
-
</div>
|
|
330
|
-
)
|
|
331
|
-
}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## 高级功能示例
|
|
335
|
-
|
|
336
|
-
### 使用购物车特性 Hooks
|
|
337
|
-
|
|
338
|
-
```tsx
|
|
339
|
-
import {
|
|
340
|
-
useCartAttributes,
|
|
341
|
-
usePriceDiscount,
|
|
342
|
-
useCalcOrderDiscount,
|
|
343
|
-
useCartItemQuantityLimit
|
|
344
|
-
} from '@anker-in/lib'
|
|
345
|
-
|
|
346
|
-
function AdvancedCart() {
|
|
347
|
-
// 购物车自定义属性
|
|
348
|
-
const { attributes, updateAttribute } = useCartAttributes()
|
|
349
|
-
|
|
350
|
-
// 价格折扣
|
|
351
|
-
const { discountedPrice } = usePriceDiscount()
|
|
352
|
-
|
|
353
|
-
// 订单折扣计算
|
|
354
|
-
const { orderDiscount } = useCalcOrderDiscount()
|
|
355
|
-
|
|
356
|
-
// 数量限制
|
|
357
|
-
const { maxQuantity, isLimitReached } = useCartItemQuantityLimit()
|
|
358
|
-
|
|
359
|
-
return (
|
|
360
|
-
<div>
|
|
361
|
-
{/* 使用这些 hooks 的数据 */}
|
|
362
|
-
</div>
|
|
363
|
-
)
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### 自定义埋点
|
|
368
|
-
|
|
369
|
-
```tsx
|
|
370
|
-
import { useBuyNow } from '@anker-in/lib'
|
|
371
|
-
|
|
372
|
-
function CustomTracking() {
|
|
373
|
-
const { trigger: buyNow } = useBuyNow({
|
|
374
|
-
withTrack: false // 禁用默认埋点
|
|
375
|
-
})
|
|
376
|
-
|
|
377
|
-
const handleBuyNow = async () => {
|
|
378
|
-
// 自定义埋点逻辑
|
|
379
|
-
window.dataLayer?.push({
|
|
380
|
-
event: 'custom_buy_now',
|
|
381
|
-
// ... 自定义数据
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
await buyNow({
|
|
385
|
-
lineItems: [/* ... */],
|
|
386
|
-
fbqTrackConfig: {
|
|
387
|
-
// Facebook Pixel 配置
|
|
388
|
-
content_ids: ['product-123'],
|
|
389
|
-
content_type: 'product',
|
|
390
|
-
value: 99.99,
|
|
391
|
-
currency: 'USD'
|
|
392
|
-
}
|
|
393
|
-
})
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return <button onClick={handleBuyNow}>购买</button>
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## TypeScript 支持
|
|
401
|
-
|
|
402
|
-
所有导出的类型都可以直接使用:
|
|
403
|
-
|
|
404
|
-
```tsx
|
|
405
|
-
import type {
|
|
406
|
-
Product,
|
|
407
|
-
Cart,
|
|
408
|
-
CartLine,
|
|
409
|
-
HeadlessConfig,
|
|
410
|
-
BuyNowArgs,
|
|
411
|
-
// ... 更多类型
|
|
412
|
-
} from '@anker-in/lib'
|
|
413
|
-
|
|
414
|
-
const config: HeadlessConfig = {
|
|
415
|
-
storefrontToken: '...',
|
|
416
|
-
storeDomain: '...',
|
|
417
|
-
// ...
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function handleProduct(product: Product) {
|
|
421
|
-
// TypeScript 完整支持
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
|
package/jest.config.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { JestConfigWithTsJest } from 'ts-jest'
|
|
2
|
-
|
|
3
|
-
const config: JestConfigWithTsJest = {
|
|
4
|
-
preset: 'ts-jest',
|
|
5
|
-
testEnvironment: 'jsdom', // 使用 node 环境(如果是浏览器库可改成 'jsdom')
|
|
6
|
-
clearMocks: true, // 每次测试后自动清除 mock
|
|
7
|
-
coverageDirectory: 'coverage', // 输出覆盖率报告
|
|
8
|
-
testMatch: ['**/__tests__/**/*.test.ts'], // 匹配测试文件路径
|
|
9
|
-
moduleFileExtensions: ['ts', 'js', 'json'],
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export default config
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { add, subtract } from '../math'
|
|
2
|
-
|
|
3
|
-
describe('math functions', () => {
|
|
4
|
-
test('add should correctly add two numbers', () => {
|
|
5
|
-
expect(add(2, 3)).toBe(5)
|
|
6
|
-
expect(add(-1, -1)).toBe(-2)
|
|
7
|
-
expect(add(0, 5)).toBe(5)
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
test('subtract should correctly subtract two numbers', () => {
|
|
11
|
-
expect(subtract(5, 3)).toBe(2)
|
|
12
|
-
expect(subtract(0, 5)).toBe(-5)
|
|
13
|
-
expect(subtract(-1, -1)).toBe(0)
|
|
14
|
-
})
|
|
15
|
-
})
|
package/src/index.ts
DELETED
package/src/math.ts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "dist",
|
|
5
|
-
"target": "esnext",
|
|
6
|
-
"module": "esnext",
|
|
7
|
-
"moduleResolution": "bundler",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"declarationMap": true,
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"lib": ["DOM", "ESNext", "DOM.Iterable"],
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"jsx": "react-jsx",
|
|
16
|
-
"types": ["jest", "node"]
|
|
17
|
-
},
|
|
18
|
-
"include": ["src"],
|
|
19
|
-
"exclude": ["node_modules", "dist"]
|
|
20
|
-
}
|
package/tsup.config.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup'
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
entry: ['src/index.ts'],
|
|
5
|
-
format: ['esm', 'cjs'],
|
|
6
|
-
dts: true,
|
|
7
|
-
splitting: false,
|
|
8
|
-
sourcemap: true,
|
|
9
|
-
clean: true,
|
|
10
|
-
external: [
|
|
11
|
-
'react',
|
|
12
|
-
'react-dom',
|
|
13
|
-
'@anker-in/shared',
|
|
14
|
-
'@anker-in/shopify',
|
|
15
|
-
'@anker-in/cart',
|
|
16
|
-
'next/router',
|
|
17
|
-
'@sentry/nextjs',
|
|
18
|
-
'swr',
|
|
19
|
-
],
|
|
20
|
-
})
|