@reni-corp/reni-2c-ui 0.3.28 → 0.3.29

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 (101) hide show
  1. package/README.md +139 -16
  2. package/dist/components/elements/Alert.vue.d.ts +21 -3
  3. package/dist/components/elements/Alert.vue.d.ts.map +1 -1
  4. package/dist/components/elements/CheckBox.vue.d.ts +42 -2
  5. package/dist/components/elements/CheckBox.vue.d.ts.map +1 -1
  6. package/dist/components/elements/ComboBox.vue.d.ts +153 -0
  7. package/dist/components/elements/ComboBox.vue.d.ts.map +1 -0
  8. package/dist/components/elements/Icon.vue.d.ts.map +1 -1
  9. package/dist/components/elements/PasswordField.vue.d.ts +75 -25
  10. package/dist/components/elements/PasswordField.vue.d.ts.map +1 -1
  11. package/dist/components/elements/Progress.vue.d.ts +45 -0
  12. package/dist/components/elements/Progress.vue.d.ts.map +1 -0
  13. package/dist/components/elements/SelectBox.vue.d.ts +30 -10
  14. package/dist/components/elements/SelectBox.vue.d.ts.map +1 -1
  15. package/dist/components/elements/SkeletonLoader.vue.d.ts +30 -0
  16. package/dist/components/elements/SkeletonLoader.vue.d.ts.map +1 -0
  17. package/dist/components/elements/SpinButton.vue.d.ts +4 -2
  18. package/dist/components/elements/SpinButton.vue.d.ts.map +1 -1
  19. package/dist/components/elements/TextField.vue.d.ts +21 -6
  20. package/dist/components/elements/TextField.vue.d.ts.map +1 -1
  21. package/dist/components/features/ProductList.vue.d.ts +4 -0
  22. package/dist/components/features/ProductList.vue.d.ts.map +1 -1
  23. package/dist/components/features/ProductListItem.vue.d.ts +4 -0
  24. package/dist/components/features/ProductListItem.vue.d.ts.map +1 -1
  25. package/dist/components/features/ProductPurchase.vue.d.ts +0 -4
  26. package/dist/components/features/ProductPurchase.vue.d.ts.map +1 -1
  27. package/dist/components/foundation/AppBar.vue.d.ts +28 -3
  28. package/dist/components/foundation/AppBar.vue.d.ts.map +1 -1
  29. package/dist/components/foundation/AppFooter.vue.d.ts +51 -1
  30. package/dist/components/foundation/AppFooter.vue.d.ts.map +1 -1
  31. package/dist/components/interactive/Disclosure.vue.d.ts +54 -0
  32. package/dist/components/interactive/Disclosure.vue.d.ts.map +1 -0
  33. package/dist/components/layouts/Page.vue.d.ts +2 -0
  34. package/dist/components/layouts/Page.vue.d.ts.map +1 -1
  35. package/dist/components/renderless/Form.vue.d.ts +27 -1
  36. package/dist/components/renderless/Form.vue.d.ts.map +1 -1
  37. package/dist/index.d.ts +9 -3
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.es.js +7161 -5941
  40. package/dist/script.es.js +8364 -7146
  41. package/dist/script.umd.js +26 -26
  42. package/dist/style.css +1 -1
  43. package/dist/types.d.ts +7 -0
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/utils.d.ts.map +1 -1
  46. package/package.json +18 -13
  47. package/src/stories/Alert.stories.ts +260 -0
  48. package/src/stories/AnnounceBar.stories.ts +138 -0
  49. package/src/stories/AppBar.stories.ts +277 -0
  50. package/src/stories/AppFooter.stories.ts +274 -0
  51. package/src/stories/AppFrame.stories.ts +46 -0
  52. package/src/stories/AppLayout.stories.ts +870 -0
  53. package/src/stories/Button.stories.ts +101 -0
  54. package/src/stories/Card.stories.ts +152 -0
  55. package/src/stories/Carousel.stories.ts +62 -0
  56. package/src/stories/CarouselBanner.stories.ts +103 -0
  57. package/src/stories/CheckBox.stories.ts +76 -0
  58. package/src/stories/ComboBox.stories.ts +524 -0
  59. package/src/stories/Dialog.stories.ts +174 -0
  60. package/src/stories/Disclosure.stories.ts +217 -0
  61. package/src/stories/Divider.stories.ts +68 -0
  62. package/src/stories/Drawer.stories.ts +135 -0
  63. package/src/stories/DropDown.stories.ts +195 -0
  64. package/src/stories/FloatingBanner.stories.ts +79 -0
  65. package/src/stories/Form.stories.ts +704 -0
  66. package/src/stories/Gallery.stories.ts +78 -0
  67. package/src/stories/Grid.stories.ts +357 -0
  68. package/src/stories/Hero.stories.ts +52 -0
  69. package/src/stories/Html.stories.ts +178 -0
  70. package/src/stories/Icon.stories.ts +176 -0
  71. package/src/stories/Image.stories.ts +613 -0
  72. package/src/stories/Label.stories.ts +54 -0
  73. package/src/stories/List.stories.ts +112 -0
  74. package/src/stories/Modal.stories.ts +123 -0
  75. package/src/stories/Notification.stories.ts +82 -0
  76. package/src/stories/Page.stories.ts +414 -0
  77. package/src/stories/PasswordField.stories.ts +304 -0
  78. package/src/stories/ProductLabels.stories.ts +65 -0
  79. package/src/stories/ProductList.stories.ts +679 -0
  80. package/src/stories/ProductPurchase.stories.ts +807 -0
  81. package/src/stories/Progress.stories.ts +192 -0
  82. package/src/stories/Radio.stories.ts +81 -0
  83. package/src/stories/Section.stories.ts +244 -0
  84. package/src/stories/SelectBox.stories.ts +377 -0
  85. package/src/stories/SkeletonLoader.stories.ts +170 -0
  86. package/src/stories/Slider.stories.ts +79 -0
  87. package/src/stories/SnsLink.stories.ts +259 -0
  88. package/src/stories/SoldStacker.stories.ts +68 -0
  89. package/src/stories/SpinButton.stories.ts +134 -0
  90. package/src/stories/Spinner.stories.ts +58 -0
  91. package/src/stories/Stack.stories.ts +104 -0
  92. package/src/stories/Switch.stories.ts +68 -0
  93. package/src/stories/Tab.stories.ts +52 -0
  94. package/src/stories/TabPanels.stories.ts +67 -0
  95. package/src/stories/Tabs.stories.ts +68 -0
  96. package/src/stories/Text.stories.ts +69 -0
  97. package/src/stories/TextArea.stories.ts +78 -0
  98. package/src/stories/TextField.stories.ts +97 -0
  99. package/src/stories/ToolChip.stories.ts +125 -0
  100. package/dist/components/elements/SkeltonLoader.vue.d.ts +0 -7
  101. package/dist/components/elements/SkeltonLoader.vue.d.ts.map +0 -1
@@ -0,0 +1,807 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import ProductPurchase, {
3
+ type ProductPurchaseProps,
4
+ } from '@/components/features/ProductPurchase.vue'
5
+ import { action } from '@storybook/addon-actions'
6
+ import { ref } from 'vue'
7
+
8
+ const meta: Meta<typeof ProductPurchase> = {
9
+ title: 'Features/ProductPurchase',
10
+ component: ProductPurchase,
11
+ tags: ['autodocs'],
12
+ parameters: {
13
+ docs: {
14
+ description: {
15
+ component:
16
+ '商品情報の表示とカートに入れる機能を持つコンポーネント。レスポンシブデザインで、スマホでは縦レイアウト、PCでは横レイアウトになります。',
17
+ },
18
+ },
19
+ },
20
+ argTypes: {
21
+ product: {
22
+ control: 'object',
23
+ description: '商品情報オブジェクト',
24
+ },
25
+ defaultVariationId: {
26
+ control: 'text',
27
+ description: '初期選択バリエーションID',
28
+ },
29
+ defaultQuantity: {
30
+ control: 'number',
31
+ description: '初期数量',
32
+ },
33
+ quantityMin: {
34
+ control: 'number',
35
+ description: '最小数量',
36
+ },
37
+ quantityMax: {
38
+ control: 'number',
39
+ description: '最大数量',
40
+ },
41
+ quantityStep: {
42
+ control: 'number',
43
+ description: '数量ステップ',
44
+ },
45
+ disabled: {
46
+ control: 'boolean',
47
+ description: '全体無効化',
48
+ },
49
+ submitting: {
50
+ control: 'boolean',
51
+ description: '送信中状態',
52
+ },
53
+ showImage: {
54
+ control: 'boolean',
55
+ description: '画像表示',
56
+ },
57
+ showQuantity: {
58
+ control: 'boolean',
59
+ description: '数量選択表示',
60
+ },
61
+ showVariation: {
62
+ control: 'boolean',
63
+ description: 'バリエーション選択表示',
64
+ },
65
+ addToCartLabel: {
66
+ control: 'text',
67
+ description: 'カートボタンのラベル',
68
+ },
69
+ // Events
70
+ addToCart: {
71
+ action: 'add-to-cart',
72
+ description: 'カートに追加時に発火するイベント',
73
+ control: false,
74
+ table: {
75
+ category: 'Events',
76
+ type: {
77
+ summary:
78
+ '(payload: { product: Product, variationId: string | null, quantity: number }) => void',
79
+ },
80
+ },
81
+ },
82
+ // Slots
83
+ description: {
84
+ control: false,
85
+ description: '商品説明を表示するスロット',
86
+ table: {
87
+ category: 'Slots',
88
+ type: {
89
+ summary: 'slot',
90
+ },
91
+ },
92
+ },
93
+ },
94
+ args: {
95
+ product: {
96
+ id: 'product-1',
97
+ title: 'Product name',
98
+ price: 3000,
99
+ price_prefix_freeWord: '各種 ',
100
+ subtitle1: 'Title1',
101
+ subtitle2: 'Title2',
102
+ imageUrls: [
103
+ 'https://placehold.jp/600x600/ff6b6b/fff?text=Product+1',
104
+ 'https://placehold.jp/600x600/4ecdc4/fff?text=Product+2',
105
+ 'https://placehold.jp/600x600/45b7d1/fff?text=Product+3',
106
+ 'https://placehold.jp/600x600/f9ca24/000?text=Product+4',
107
+ ],
108
+ variations: [
109
+ { id: 'var1', label: 'ホワイト / S', available: true },
110
+ { id: 'var2', label: 'ブラック / S', available: true },
111
+ { id: 'var3', label: 'ホワイト / M', available: true },
112
+ { id: 'var4', label: 'ブラック / M', available: false },
113
+ ],
114
+ },
115
+ defaultQuantity: 1,
116
+ quantityMin: 1,
117
+ quantityMax: 99,
118
+ quantityStep: 1,
119
+ disabled: false,
120
+ submitting: false,
121
+ showImage: true,
122
+ showQuantity: true,
123
+ showVariation: true,
124
+ addToCartLabel: 'カートに入れる',
125
+ },
126
+ }
127
+
128
+ export default meta
129
+ type StoryArgs = ProductPurchaseProps
130
+ type Story = StoryObj<StoryArgs>
131
+
132
+ // モックの商品データ
133
+ const createMockProduct = (overrides = {}) => ({
134
+ id: 'product-1',
135
+ title: 'オフィシャルTシャツ',
136
+ price: 3500,
137
+ price_prefix_freeWord: '各種 ',
138
+ subtitle1: 'RENI',
139
+ subtitle2: 'Official Merchandise',
140
+ imageUrls: [
141
+ 'https://placehold.jp/600x600/ff6b6b/fff?text=Product+Front',
142
+ 'https://placehold.jp/600x600/4ecdc4/fff?text=Product+Back',
143
+ 'https://placehold.jp/600x600/45b7d1/fff?text=Detail+1',
144
+ 'https://placehold.jp/600x600/f9ca24/000?text=Detail+2',
145
+ 'https://placehold.jp/600x600/6c5ce7/fff?text=Model+Wear',
146
+ ],
147
+ variations: [
148
+ { id: 'white-s', label: 'ホワイト / S', available: true },
149
+ { id: 'white-m', label: 'ホワイト / M', available: true },
150
+ { id: 'white-l', label: 'ホワイト / L', available: true },
151
+ { id: 'black-s', label: 'ブラック / S', available: true },
152
+ { id: 'black-m', label: 'ブラック / M', available: true },
153
+ { id: 'black-l', label: 'ブラック / L', available: false },
154
+ ],
155
+ ...overrides,
156
+ })
157
+
158
+ export const 価格プレフィックスなし: Story = {
159
+ args: {
160
+ product: createMockProduct({
161
+ price_prefix_freeWord: '', // プレフィックスなし
162
+ price: 2980,
163
+ }),
164
+ },
165
+ render: (args: StoryArgs) => ({
166
+ components: {
167
+ 'rn-product-purchase': ProductPurchase,
168
+ },
169
+ setup() {
170
+ const handleAddToCart = action('add-to-cart')
171
+ return { args, handleAddToCart }
172
+ },
173
+ template: `
174
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
175
+ <h3>価格プレフィックスなし</h3>
176
+ <rn-product-purchase
177
+ v-bind="args"
178
+ @add-to-cart="handleAddToCart"
179
+ />
180
+ </div>
181
+ `,
182
+ }),
183
+ }
184
+
185
+ export const 基本表示: Story = {
186
+ args: {
187
+ product: createMockProduct(),
188
+ },
189
+ render: (args: StoryArgs) => ({
190
+ components: {
191
+ 'rn-product-purchase': ProductPurchase,
192
+ },
193
+ setup() {
194
+ const handleAddToCart = action('add-to-cart')
195
+ return { args, handleAddToCart }
196
+ },
197
+ template: `
198
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
199
+ <h3>基本表示</h3>
200
+ <rn-product-purchase
201
+ v-bind="args"
202
+ @add-to-cart="handleAddToCart"
203
+ />
204
+ </div>
205
+ `,
206
+ }),
207
+ }
208
+
209
+ export const 単一バリエーション_I_F確認: Story = {
210
+ args: {
211
+ product: createMockProduct({
212
+ variations: [
213
+ { id: 'only-variation', label: 'ワンサイズ', available: true },
214
+ ],
215
+ imageUrls: [
216
+ 'https://placehold.jp/600x600/27ae60/fff?text=Single+Variation',
217
+ ],
218
+ }),
219
+ },
220
+ render: (args: StoryArgs) => ({
221
+ components: {
222
+ 'rn-product-purchase': ProductPurchase,
223
+ },
224
+ setup() {
225
+ const submitting = ref(false)
226
+ const disabled = ref(false)
227
+ const lastAddToCartData = ref<any>(null)
228
+
229
+ const handleAddToCart = async (payload: any) => {
230
+ action('add-to-cart')(payload)
231
+
232
+ // I/F情報を保存
233
+ lastAddToCartData.value = payload
234
+
235
+ // 送信中状態をシミュレート
236
+ submitting.value = true
237
+
238
+ await new Promise((resolve) => setTimeout(resolve, 1500))
239
+
240
+ submitting.value = false
241
+ }
242
+
243
+ const toggleDisabled = () => {
244
+ disabled.value = !disabled.value
245
+ }
246
+
247
+ const clearData = () => {
248
+ lastAddToCartData.value = null
249
+ }
250
+
251
+ return {
252
+ args,
253
+ handleAddToCart,
254
+ submitting,
255
+ disabled,
256
+ toggleDisabled,
257
+ lastAddToCartData,
258
+ clearData,
259
+ }
260
+ },
261
+ template: `
262
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
263
+ <h3>🔍 単一バリエーション addToCart I/F確認</h3>
264
+ <div style="margin-bottom: 16px;">
265
+ <button @click="toggleDisabled" style="padding: 8px 16px; margin-right: 8px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
266
+ {{ disabled ? '有効化' : '無効化' }}
267
+ </button>
268
+ <button v-if="lastAddToCartData" @click="clearData" style="padding: 8px 16px; margin-right: 8px; background: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer;">
269
+ データをクリア
270
+ </button>
271
+ <span style="color: #6c757d;">※ セレクトボックスが非表示でも、カートに追加時にvariationIdが渡されることを確認</span>
272
+ </div>
273
+
274
+ <!-- addToCartイベントのI/F表示 -->
275
+ <div v-if="lastAddToCartData" style="background: #d4edda; border: 1px solid #27ae60; border-radius: 8px; padding: 20px; margin-bottom: 24px;">
276
+ <h4 style="margin-top: 0; color: #27ae60; display: flex; align-items: center;">
277
+ <span style="margin-right: 8px;">🎯</span>
278
+ addToCart イベントデータ(単一バリエーション)
279
+ </h4>
280
+
281
+ <div style="background: #ffffff; padding: 16px; border-radius: 6px; margin-bottom: 16px;">
282
+ <pre style="margin: 0; overflow-x: auto; font-size: 14px; line-height: 1.4;">{{ JSON.stringify(lastAddToCartData, null, 2) }}</pre>
283
+ </div>
284
+
285
+ <div style="font-size: 14px; color: #495057;">
286
+ <h5 style="margin: 0 0 8px 0; color: #27ae60;">✅ 重要ポイント</h5>
287
+ <div style="background: #f8f9fa; padding: 12px; border-radius: 4px; border-left: 4px solid #27ae60;">
288
+ <div style="margin-bottom: 8px;">• セレクトボックスは非表示(バリエーションが1つのため)</div>
289
+ <div style="margin-bottom: 8px;">• <code style="background: #e9ecef; padding: 2px 6px; border-radius: 3px;">variationId</code> には自動で "only-variation" が設定される</div>
290
+ <div style="margin-bottom: 8px;">• ユーザーは選択操作なしでカートに追加可能</div>
291
+ <div>• バリエーション情報は確実に渡される</div>
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ <rn-product-purchase
297
+ v-bind="args"
298
+ :submitting="submitting"
299
+ :disabled="disabled"
300
+ @add-to-cart="handleAddToCart"
301
+ >
302
+ <template #description>
303
+ <div style="padding: 16px; background: #d1ecf1; border: 1px solid #17a2b8; border-radius: 8px; margin-top: 16px;">
304
+ <h4>📝 動作確認ポイント</h4>
305
+ <ul style="margin: 8px 0; padding-left: 20px;">
306
+ <li>バリエーション選択エリアが表示されない</li>
307
+ <li>「カートに入れる」ボタンがすぐに押せる</li>
308
+ <li>AddCart時にvariationId="only-variation"が渡される</li>
309
+ <li>ユーザー体験として自然な流れ</li>
310
+ </ul>
311
+ </div>
312
+ </template>
313
+ </rn-product-purchase>
314
+ </div>
315
+ `,
316
+ }),
317
+ }
318
+
319
+ export const addToCartI_F確認: Story = {
320
+ args: {
321
+ product: createMockProduct(),
322
+ },
323
+ render: (args: StoryArgs) => ({
324
+ components: {
325
+ 'rn-product-purchase': ProductPurchase,
326
+ },
327
+ setup() {
328
+ const submitting = ref(false)
329
+ const disabled = ref(false)
330
+ const lastAddToCartData = ref<any>(null)
331
+
332
+ const handleAddToCart = async (payload: any) => {
333
+ action('add-to-cart')(payload)
334
+
335
+ // I/F情報を保存
336
+ lastAddToCartData.value = payload
337
+
338
+ // 送信中状態をシミュレート
339
+ submitting.value = true
340
+
341
+ await new Promise((resolve) => setTimeout(resolve, 1500))
342
+
343
+ submitting.value = false
344
+ }
345
+
346
+ const toggleDisabled = () => {
347
+ disabled.value = !disabled.value
348
+ }
349
+
350
+ const clearData = () => {
351
+ lastAddToCartData.value = null
352
+ }
353
+
354
+ return {
355
+ args,
356
+ handleAddToCart,
357
+ submitting,
358
+ disabled,
359
+ toggleDisabled,
360
+ lastAddToCartData,
361
+ clearData,
362
+ }
363
+ },
364
+ template: `
365
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
366
+ <h3>🔍 addToCart イベントI/F確認(複数バリエーション)</h3>
367
+ <div style="margin-bottom: 16px;">
368
+ <button @click="toggleDisabled" style="padding: 8px 16px; margin-right: 8px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
369
+ {{ disabled ? '有効化' : '無効化' }}
370
+ </button>
371
+ <button v-if="lastAddToCartData" @click="clearData" style="padding: 8px 16px; margin-right: 8px; background: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer;">
372
+ データをクリア
373
+ </button>
374
+ <span style="color: #6c757d;">※ カートに追加ボタンを押すと、下にイベントデータが表示されます</span>
375
+ </div>
376
+
377
+ <!-- addToCartイベントのI/F表示 -->
378
+ <div v-if="lastAddToCartData" style="background: #d1edff; border: 1px solid #0066cc; border-radius: 8px; padding: 20px; margin-bottom: 24px;">
379
+ <h4 style="margin-top: 0; color: #0066cc; display: flex; align-items: center;">
380
+ <span style="margin-right: 8px;">🎯</span>
381
+ addToCart イベントデータ
382
+ </h4>
383
+
384
+ <div style="background: #ffffff; padding: 16px; border-radius: 6px; margin-bottom: 16px;">
385
+ <pre style="margin: 0; overflow-x: auto; font-size: 14px; line-height: 1.4;">{{ JSON.stringify(lastAddToCartData, null, 2) }}</pre>
386
+ </div>
387
+
388
+ <div style="font-size: 14px; color: #495057;">
389
+ <h5 style="margin: 0 0 8px 0; color: #0066cc;">📋 イベントI/F仕様</h5>
390
+ <div style="background: #f8f9fa; padding: 12px; border-radius: 4px; border-left: 4px solid #0066cc;">
391
+ <div style="margin-bottom: 8px;"><code style="background: #e9ecef; padding: 2px 6px; border-radius: 3px;">product</code>: 商品オブジェクト (object)</div>
392
+ <div style="padding-left: 16px; font-size: 13px; color: #6c757d; margin-bottom: 8px;">
393
+ • id, title, price, subtitle1, subtitle2, imageUrls, variations を含む
394
+ </div>
395
+ <div style="margin-bottom: 8px;"><code style="background: #e9ecef; padding: 2px 6px; border-radius: 3px;">variationId</code>: 選択バリエーションID (string | null)</div>
396
+ <div style="padding-left: 16px; font-size: 13px; color: #6c757d; margin-bottom: 8px;">
397
+ • バリエーションが選択されていない場合はnull
398
+ </div>
399
+ <div><code style="background: #e9ecef; padding: 2px 6px; border-radius: 3px;">quantity</code>: 選択数量 (number)</div>
400
+ <div style="padding-left: 16px; font-size: 13px; color: #6c757d;">
401
+ • SpinButtonで選択された数量
402
+ </div>
403
+ </div>
404
+ </div>
405
+ </div>
406
+
407
+ <rn-product-purchase
408
+ v-bind="args"
409
+ :submitting="submitting"
410
+ :disabled="disabled"
411
+ @add-to-cart="handleAddToCart"
412
+ >
413
+ <template #description>
414
+ <div style="padding: 16px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 8px; margin-top: 16px;">
415
+ <h4>💡 使用方法</h4>
416
+ <ol style="margin: 8px 0; padding-left: 20px;">
417
+ <li>バリエーション(サイズ・カラー)を選択</li>
418
+ <li>数量を調整</li>
419
+ <li>「カートに入れる」ボタンをクリック</li>
420
+ <li>上に表示されるイベントデータを確認</li>
421
+ </ol>
422
+ <p style="margin: 8px 0 0 0; font-size: 14px; color: #856404;">
423
+ <strong>Actionsタブ</strong> でも同じデータを確認できます。
424
+ </p>
425
+ </div>
426
+ </template>
427
+ </rn-product-purchase>
428
+ </div>
429
+ `,
430
+ }),
431
+ }
432
+
433
+ export const 説明スロット付き: Story = {
434
+ args: {
435
+ product: createMockProduct(),
436
+ },
437
+ render: (args: StoryArgs) => ({
438
+ components: {
439
+ 'rn-product-purchase': ProductPurchase,
440
+ },
441
+ setup() {
442
+ const handleAddToCart = action('add-to-cart')
443
+ return { args, handleAddToCart }
444
+ },
445
+ template: `
446
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
447
+ <h3>説明スロット付き</h3>
448
+ <rn-product-purchase
449
+ v-bind="args"
450
+ @add-to-cart="handleAddToCart"
451
+ >
452
+ <template #description>
453
+ <div style="padding: 16px; background: #f5f5f5; border-radius: 8px; margin-top: 16px;">
454
+ <p><strong>商品説明</strong></p>
455
+ <p>こちらはProductの公式グッズです。高品質なコットン100%で作られており、着心地抜群です。</p>
456
+ <ul>
457
+ <li>素材:コットン100%</li>
458
+ <li>サイズ:S, M, L展開</li>
459
+ <li>カラー:ホワイト、ブラック</li>
460
+ <li>洗濯:冷水で手洗い推奨</li>
461
+ </ul>
462
+ </div>
463
+ </template>
464
+ </rn-product-purchase>
465
+ </div>
466
+ `,
467
+ }),
468
+ }
469
+
470
+ export const バリエーション無し: Story = {
471
+ args: {
472
+ product: createMockProduct({
473
+ variations: [],
474
+ imageUrls: [
475
+ 'https://placehold.jp/600x600/f39c12/fff?text=Single+Image+Product',
476
+ ],
477
+ }),
478
+ showVariation: false,
479
+ },
480
+ render: (args: StoryArgs) => ({
481
+ components: {
482
+ 'rn-product-purchase': ProductPurchase,
483
+ },
484
+ setup() {
485
+ const handleAddToCart = action('add-to-cart')
486
+ return { args, handleAddToCart }
487
+ },
488
+ template: `
489
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
490
+ <h3>バリエーション無し</h3>
491
+ <rn-product-purchase
492
+ v-bind="args"
493
+ @add-to-cart="handleAddToCart"
494
+ />
495
+ </div>
496
+ `,
497
+ }),
498
+ }
499
+
500
+ export const 単一バリエーション: Story = {
501
+ args: {
502
+ product: createMockProduct({
503
+ variations: [{ id: 'only-one', label: 'フリーサイズ', available: true }],
504
+ imageUrls: [
505
+ 'https://placehold.jp/600x600/e74c3c/fff?text=Free+Size+Only',
506
+ ],
507
+ }),
508
+ },
509
+ render: (args: StoryArgs) => ({
510
+ components: {
511
+ 'rn-product-purchase': ProductPurchase,
512
+ },
513
+ setup() {
514
+ const handleAddToCart = action('add-to-cart')
515
+ return { args, handleAddToCart }
516
+ },
517
+ template: `
518
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
519
+ <h3>単一バリエーション(セレクトボックス非表示・自動選択)</h3>
520
+ <p style="color: #666; margin-bottom: 16px;">バリエーションが1つの場合、セレクトボックスは表示されず、AddCart時に暗黙的にそのバリエーションが選択されます。</p>
521
+ <rn-product-purchase
522
+ v-bind="args"
523
+ @add-to-cart="handleAddToCart"
524
+ />
525
+ </div>
526
+ `,
527
+ }),
528
+ }
529
+
530
+ export const 画像無し: Story = {
531
+ args: {
532
+ product: createMockProduct({
533
+ imageUrls: [],
534
+ }),
535
+ showImage: false,
536
+ },
537
+ render: (args: StoryArgs) => ({
538
+ components: {
539
+ 'rn-product-purchase': ProductPurchase,
540
+ },
541
+ setup() {
542
+ const handleAddToCart = action('add-to-cart')
543
+ return { args, handleAddToCart }
544
+ },
545
+ template: `
546
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
547
+ <h3>画像無し</h3>
548
+ <rn-product-purchase
549
+ v-bind="args"
550
+ @add-to-cart="handleAddToCart"
551
+ />
552
+ </div>
553
+ `,
554
+ }),
555
+ }
556
+
557
+ export const 数量制限: Story = {
558
+ args: {
559
+ product: createMockProduct(),
560
+ quantityMin: 2,
561
+ quantityMax: 5,
562
+ defaultQuantity: 2,
563
+ },
564
+ render: (args: StoryArgs) => ({
565
+ components: {
566
+ 'rn-product-purchase': ProductPurchase,
567
+ },
568
+ setup() {
569
+ const handleAddToCart = action('add-to-cart')
570
+ return { args, handleAddToCart }
571
+ },
572
+ template: `
573
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
574
+ <h3>数量制限(最小2個、最大5個)</h3>
575
+ <rn-product-purchase
576
+ v-bind="args"
577
+ @add-to-cart="handleAddToCart"
578
+ />
579
+ </div>
580
+ `,
581
+ }),
582
+ }
583
+
584
+ export const 無効化状態: Story = {
585
+ args: {
586
+ product: createMockProduct(),
587
+ disabled: true,
588
+ },
589
+ render: (args: StoryArgs) => ({
590
+ components: {
591
+ 'rn-product-purchase': ProductPurchase,
592
+ },
593
+ setup() {
594
+ const handleAddToCart = action('add-to-cart')
595
+ return { args, handleAddToCart }
596
+ },
597
+ template: `
598
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
599
+ <h3>無効化状態</h3>
600
+ <rn-product-purchase
601
+ v-bind="args"
602
+ @add-to-cart="handleAddToCart"
603
+ />
604
+ </div>
605
+ `,
606
+ }),
607
+ }
608
+
609
+ export const 送信中状態: Story = {
610
+ args: {
611
+ product: createMockProduct(),
612
+ submitting: true,
613
+ },
614
+ render: (args: StoryArgs) => ({
615
+ components: {
616
+ 'rn-product-purchase': ProductPurchase,
617
+ },
618
+ setup() {
619
+ const handleAddToCart = action('add-to-cart')
620
+ return { args, handleAddToCart }
621
+ },
622
+ template: `
623
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
624
+ <h3>送信中状態</h3>
625
+ <rn-product-purchase
626
+ v-bind="args"
627
+ @add-to-cart="handleAddToCart"
628
+ />
629
+ </div>
630
+ `,
631
+ }),
632
+ }
633
+
634
+ export const カスタムボタンテキスト: Story = {
635
+ args: {
636
+ product: createMockProduct(),
637
+ addToCartLabel: '今すぐ購入',
638
+ },
639
+ render: (args: StoryArgs) => ({
640
+ components: {
641
+ 'rn-product-purchase': ProductPurchase,
642
+ },
643
+ setup() {
644
+ const handleAddToCart = action('add-to-cart')
645
+ return { args, handleAddToCart }
646
+ },
647
+ template: `
648
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
649
+ <h3>カスタムボタンテキスト</h3>
650
+ <rn-product-purchase
651
+ v-bind="args"
652
+ @add-to-cart="handleAddToCart"
653
+ />
654
+ </div>
655
+ `,
656
+ }),
657
+ }
658
+
659
+ export const 最小構成: Story = {
660
+ args: {
661
+ product: createMockProduct({
662
+ subtitle1: undefined,
663
+ subtitle2: undefined,
664
+ imageUrls: [],
665
+ variations: [],
666
+ }),
667
+ showImage: false,
668
+ showVariation: false,
669
+ showQuantity: false,
670
+ },
671
+ render: (args: StoryArgs) => ({
672
+ components: {
673
+ 'rn-product-purchase': ProductPurchase,
674
+ },
675
+ setup() {
676
+ const handleAddToCart = action('add-to-cart')
677
+ return { args, handleAddToCart }
678
+ },
679
+ template: `
680
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
681
+ <h3>最小構成(タイトルとボタンのみ)</h3>
682
+ <rn-product-purchase
683
+ v-bind="args"
684
+ @add-to-cart="handleAddToCart"
685
+ />
686
+ </div>
687
+ `,
688
+ }),
689
+ }
690
+
691
+ export const インタラクティブデモ: Story = {
692
+ args: {
693
+ product: createMockProduct(),
694
+ },
695
+ render: (args: StoryArgs) => ({
696
+ components: {
697
+ 'rn-product-purchase': ProductPurchase,
698
+ },
699
+ setup() {
700
+ const submitting = ref(false)
701
+ const disabled = ref(false)
702
+
703
+ const handleAddToCart = async (payload: any) => {
704
+ action('add-to-cart')(payload)
705
+
706
+ // 送信中状態をシミュレート
707
+ submitting.value = true
708
+
709
+ await new Promise((resolve) => setTimeout(resolve, 2000))
710
+
711
+ submitting.value = false
712
+ alert(
713
+ `カートに追加しました!\n商品ID: ${payload.product.id}\nバリエーション: ${payload.variationId}\n数量: ${payload.quantity}個`,
714
+ )
715
+ }
716
+
717
+ const toggleDisabled = () => {
718
+ disabled.value = !disabled.value
719
+ }
720
+
721
+ return {
722
+ args,
723
+ handleAddToCart,
724
+ submitting,
725
+ disabled,
726
+ toggleDisabled,
727
+ }
728
+ },
729
+ template: `
730
+ <div class="sb-canvas" style="padding: 20px; max-width: 1200px;">
731
+ <h3>インタラクティブデモ</h3>
732
+ <div style="margin-bottom: 16px;">
733
+ <button @click="toggleDisabled" style="padding: 8px 16px; margin-right: 8px;">
734
+ {{ disabled ? '有効化' : '無効化' }}
735
+ </button>
736
+ <span>※カートに追加すると送信中状態をシミュレートします</span>
737
+ </div>
738
+
739
+ <rn-product-purchase
740
+ v-bind="args"
741
+ :submitting="submitting"
742
+ :disabled="disabled"
743
+ @add-to-cart="handleAddToCart"
744
+ >
745
+ <template #description>
746
+ <div style="padding: 16px; background: #f0f8ff; border: 1px solid #b3d9ff; border-radius: 8px; margin-top: 16px;">
747
+ <h4>🎵 RENI オフィシャルグッズ</h4>
748
+ <p>RENIの公式Tシャツです。ファン必見のアイテム!</p>
749
+ <p><strong>特徴:</strong></p>
750
+ <ul>
751
+ <li>高品質プリント技術を使用</li>
752
+ <li>着心地の良いコットン素材</li>
753
+ <li>オフィシャルライセンス商品</li>
754
+ <li>数量限定生産</li>
755
+ </ul>
756
+ </div>
757
+ </template>
758
+ </rn-product-purchase>
759
+ </div>
760
+ `,
761
+ }),
762
+ }
763
+
764
+ export const レスポンシブプレビュー: Story = {
765
+ args: {
766
+ product: createMockProduct(),
767
+ },
768
+ render: (args: StoryArgs) => ({
769
+ components: {
770
+ 'rn-product-purchase': ProductPurchase,
771
+ },
772
+ setup() {
773
+ const handleAddToCart = action('add-to-cart')
774
+ return { args, handleAddToCart }
775
+ },
776
+ template: `
777
+ <div class="sb-canvas" style="padding: 20px;">
778
+ <h3>レスポンシブプレビュー</h3>
779
+ <p>ブラウザの幅を変更して、レイアウトの変化を確認してください。</p>
780
+ <p>768px未満:縦レイアウト(画像上、情報下)</p>
781
+ <p>768px以上:横レイアウト(画像左、情報右)</p>
782
+
783
+ <!-- PCレイアウトプレビュー -->
784
+ <div style="margin-bottom: 40px;">
785
+ <h4>PCレイアウト (768px以上)</h4>
786
+ <div style="min-width: 800px; border: 2px dashed #ccc; padding: 16px;">
787
+ <rn-product-purchase
788
+ v-bind="args"
789
+ @add-to-cart="handleAddToCart"
790
+ />
791
+ </div>
792
+ </div>
793
+
794
+ <!-- スマホレイアウトプレビュー -->
795
+ <div>
796
+ <h4>スマホレイアウト (767px以下)</h4>
797
+ <div style="max-width: 375px; border: 2px dashed #ccc; padding: 16px;">
798
+ <rn-product-purchase
799
+ v-bind="args"
800
+ @add-to-cart="handleAddToCart"
801
+ />
802
+ </div>
803
+ </div>
804
+ </div>
805
+ `,
806
+ }),
807
+ }