@reshape-biotech/design-system 0.0.49 → 0.0.50

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.
@@ -0,0 +1,227 @@
1
+ <script module lang="ts">
2
+ import { defineMeta } from '@storybook/addon-svelte-csf';
3
+ import { userEvent, within } from '@storybook/test';
4
+ import { DateTime } from 'luxon';
5
+ import DatePicker from './DatePicker.svelte';
6
+ import Dropdown from '../dropdown/Dropdown.svelte';
7
+ import Button from '../button/Button.svelte';
8
+ import { Icon } from '../icons';
9
+
10
+ const { Story } = defineMeta({
11
+ component: DatePicker,
12
+ title: 'Design System/DatePicker',
13
+ tags: ['autodocs'],
14
+ parameters: {
15
+ design: {
16
+ type: 'figma',
17
+ url: 'https://www.figma.com/design/WkxhG4H2Ybc7STFi1VJIau/%F0%9F%92%A0-Reshape-Design-System%3A-V1?node-id=4381-32638&t=Epi2Ul7Cw7sCJpGy-0'
18
+ }
19
+ }
20
+ });
21
+
22
+ let selectedDate = $state<DateTime | undefined>(undefined);
23
+ let loggedDate = $state<string | undefined>(undefined);
24
+
25
+ function handleDateSelection(date: DateTime) {
26
+ loggedDate = date.toFormat('yyyy-MM-dd');
27
+ }
28
+
29
+ // States for the dropdown story
30
+ let dropdownDate = $state<DateTime | undefined>(undefined);
31
+ let displayText = $state('Select a date');
32
+ let isOpen = $state(false);
33
+
34
+ // States for the form test
35
+ let formDropdownDate = $state<DateTime | undefined>(undefined);
36
+ let formDisplayText = $state('Select a date');
37
+ let formIsOpen = $state(false);
38
+
39
+ function handleDropdownSelection(date: DateTime) {
40
+ dropdownDate = date;
41
+ displayText = date.toFormat('MMM dd, yyyy');
42
+ isOpen = false;
43
+ }
44
+
45
+ function handleFormDateSelection(date: DateTime) {
46
+ formDropdownDate = date;
47
+ formDisplayText = date.toFormat('MMM dd, yyyy');
48
+ formIsOpen = false;
49
+ }
50
+ </script>
51
+
52
+ <Story name="Default">
53
+ <div class="p-4">
54
+ <DatePicker bind:selectedDate />
55
+ </div>
56
+ </Story>
57
+
58
+ <Story name="With Selected Date">
59
+ <div class="p-4">
60
+ <DatePicker selectedDate={DateTime.local(2023, 10, 15)} />
61
+ </div>
62
+ </Story>
63
+
64
+ <Story name="With Date Change Handler">
65
+ <div class="p-4">
66
+ <div class="mb-4">
67
+ <DatePicker {selectedDate} onClick={handleDateSelection} />
68
+ </div>
69
+ {#if loggedDate}
70
+ <div class="mt-4 rounded bg-neutral p-2">
71
+ <p>Selected date: <strong>{loggedDate}</strong></p>
72
+ </div>
73
+ {/if}
74
+ </div>
75
+ </Story>
76
+
77
+ <Story name="Month Navigation">
78
+ <div class="p-4">
79
+ <DatePicker selectedDate={DateTime.local()} />
80
+ <div class="mt-4 text-sm text-tertiary">
81
+ <p>Click the arrow buttons to navigate between months</p>
82
+ </div>
83
+ </div>
84
+ </Story>
85
+
86
+ <Story
87
+ name="Interaction Test"
88
+ play={async ({ canvasElement }) => {
89
+ const canvas = within(canvasElement);
90
+
91
+ // Click next month button
92
+ const nextMonthButton = canvas.getAllByRole('button')[1]; // Second button is next month
93
+ await userEvent.click(nextMonthButton);
94
+
95
+ // Wait a moment
96
+ await new Promise((resolve) => setTimeout(resolve, 300));
97
+
98
+ // Click a date (the 15th of the month)
99
+ const dateButtons = canvas.getAllByRole('button').filter((button) => {
100
+ // Find buttons with just numbers as their text content
101
+ const text = button.textContent?.trim();
102
+ return text && !isNaN(Number(text));
103
+ });
104
+
105
+ // Find the button with text "15" if it exists
106
+ const date15Button = dateButtons.find((button) => button.textContent?.trim() === '15');
107
+
108
+ if (date15Button) {
109
+ await userEvent.click(date15Button);
110
+ }
111
+ }}
112
+ >
113
+ <div class="p-4">
114
+ <DatePicker bind:selectedDate />
115
+ {#if selectedDate}
116
+ <div class="mt-4 rounded bg-neutral p-2">
117
+ <p>Selected date: <strong>{selectedDate.toFormat('yyyy-MM-dd')}</strong></p>
118
+ </div>
119
+ {/if}
120
+ </div>
121
+ </Story>
122
+
123
+ <Story name="Multiple DatePickers">
124
+ <div class="flex flex-col gap-4 p-4 md:flex-row">
125
+ <div>
126
+ <h3 class="mb-2 text-sm font-medium">Start Date</h3>
127
+ <DatePicker selectedDate={DateTime.local().minus({ days: 7 })} />
128
+ </div>
129
+ <div>
130
+ <h3 class="mb-2 text-sm font-medium">End Date</h3>
131
+ <DatePicker selectedDate={DateTime.local()} />
132
+ </div>
133
+ </div>
134
+ </Story>
135
+
136
+ <Story name="In Dropdown">
137
+ <div class="p-4">
138
+ <Dropdown bind:open={isOpen} side="dropdown-bottom" alignEnd={false}>
139
+ {#snippet trigger({ Trigger })}
140
+ <Trigger>
141
+ <Icon iconName="CalendarBlank" class="mr-2" size={16} />
142
+ {displayText}
143
+ </Trigger>
144
+ {/snippet}
145
+
146
+ {#snippet content()}
147
+ <DatePicker selectedDate={dropdownDate} onClick={handleDropdownSelection} />
148
+ {/snippet}
149
+ </Dropdown>
150
+
151
+ {#if dropdownDate}
152
+ <div class="mt-4 rounded bg-neutral p-2">
153
+ <p>You selected: <strong>{dropdownDate.toFormat('MMMM dd, yyyy')}</strong></p>
154
+ </div>
155
+ {/if}
156
+ </div>
157
+ </Story>
158
+
159
+ <Story
160
+ name="Form Submit Prevention Test"
161
+ play={async ({ canvasElement }) => {
162
+ const canvas = within(canvasElement);
163
+
164
+ // Setup spy on form submission
165
+ const form = canvas.getByTestId('test-form');
166
+ let submissionCount = 0;
167
+ form.addEventListener('submit', (e) => {
168
+ e.preventDefault();
169
+ submissionCount++;
170
+ console.log('Form was submitted!');
171
+ });
172
+
173
+ // First open the dropdown
174
+ const dropdownTrigger = canvas.getByTestId('form-date-trigger');
175
+ await userEvent.click(dropdownTrigger);
176
+
177
+ // Click prev/next month and verify no submission
178
+ const buttons = document.querySelectorAll('button');
179
+ const prevMonthButton = Array.from(buttons).find((btn) => btn.innerHTML.includes('CaretLeft'));
180
+ const nextMonthButton = Array.from(buttons).find((btn) => btn.innerHTML.includes('CaretRight'));
181
+
182
+ if (prevMonthButton) {
183
+ await userEvent.click(prevMonthButton);
184
+ console.log('Clicked prev month, submission count:', submissionCount);
185
+ }
186
+
187
+ if (nextMonthButton) {
188
+ await userEvent.click(nextMonthButton);
189
+ console.log('Clicked next month, submission count:', submissionCount);
190
+ }
191
+
192
+ // Success message if no form submission occurred
193
+ if (submissionCount === 0) {
194
+ console.log('TEST PASSED: Month navigation did not trigger form submission');
195
+ } else {
196
+ console.error('TEST FAILED: Month navigation triggered form submission');
197
+ }
198
+ }}
199
+ >
200
+ <div class="p-4">
201
+ <form data-testid="test-form" onsubmit={(e) => e.preventDefault()}>
202
+ <div class="mb-4">
203
+ <label for="name" class="mb-1 block text-sm font-medium">Name</label>
204
+ <input id="name" type="text" class="input input-bordered w-full" />
205
+ </div>
206
+
207
+ <div class="mb-4">
208
+ <Dropdown bind:open={formIsOpen} side="dropdown-bottom" alignEnd={false}>
209
+ {#snippet trigger({ Trigger })}
210
+ <Trigger>
211
+ <div data-testid="form-date-trigger" class="flex items-center gap-2">
212
+ <Icon iconName="CalendarBlank" class="mr-2" size={16} />
213
+ {formDisplayText}
214
+ </div>
215
+ </Trigger>
216
+ {/snippet}
217
+
218
+ {#snippet content()}
219
+ <DatePicker selectedDate={formDropdownDate} onClick={handleFormDateSelection} />
220
+ {/snippet}
221
+ </Dropdown>
222
+ </div>
223
+
224
+ <button type="submit" class="btn btn-primary mt-4">Submit Form</button>
225
+ </form>
226
+ </div>
227
+ </Story>
@@ -0,0 +1,19 @@
1
+ import DatePicker from './DatePicker.svelte';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const DatePicker: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type DatePicker = InstanceType<typeof DatePicker>;
19
+ export default DatePicker;
@@ -95,11 +95,11 @@
95
95
  <div class="calendar">
96
96
  <div class="calendar-header">
97
97
  <div class="month-year">
98
- <IconButton onclick={previousMonth}>
98
+ <IconButton onclick={previousMonth} type="button">
99
99
  <Icon iconName="CaretLeft" color="secondary" size="0.75rem" />
100
100
  </IconButton>
101
101
  <h5>{DateTime.local(shownYear, shownMonth).toFormat('MMM yyyy')}</h5>
102
- <IconButton onclick={nextMonth}>
102
+ <IconButton onclick={nextMonth} type="button">
103
103
  <Icon iconName="CaretRight" color="secondary" size="0.75rem" />
104
104
  </IconButton>
105
105
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reshape-biotech/design-system",
3
- "version": "0.0.49",
3
+ "version": "0.0.50",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build",
@@ -36,7 +36,8 @@
36
36
  "svelte": "^5.0.0",
37
37
  "marked": "^15.0.0",
38
38
  "luxon": "^3.5.0",
39
- "svelte-select": "^5.8.1"
39
+ "svelte-select": "^5.8.1",
40
+ "echarts": "^5.6.0"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@eslint/compat": "^1.2.3",