@makolabs/ripple 3.0.1 → 3.0.3

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.
@@ -45,12 +45,12 @@
45
45
  const toggleSize = $derived(
46
46
  (
47
47
  {
48
- [Size.XS]: 'w-6 h-3',
49
- [Size.SM]: 'w-7 h-3.5',
50
- [Size.MD]: 'w-8 h-4',
51
- [Size.LG]: 'w-10 h-5',
52
- [Size.XL]: 'w-12 h-6',
53
- [Size.XXL]: 'w-12 h-6'
48
+ [Size.XS]: 'w-7 h-3.5',
49
+ [Size.SM]: 'w-8 h-4',
50
+ [Size.MD]: 'w-10 h-5',
51
+ [Size.LG]: 'w-12 h-6',
52
+ [Size.XL]: 'w-14 h-7',
53
+ [Size.XXL]: 'w-14 h-7'
54
54
  } satisfies Record<VariantSizes, string>
55
55
  )[size]
56
56
  );
@@ -58,12 +58,12 @@
58
58
  const thumbSize = $derived(
59
59
  (
60
60
  {
61
- [Size.XS]: 'h-2 w-2',
62
- [Size.SM]: 'h-2.5 w-2.5',
63
- [Size.MD]: 'h-3 w-3',
64
- [Size.LG]: 'h-4 w-4',
65
- [Size.XL]: 'h-5 w-5',
66
- [Size.XXL]: 'h-5 w-5'
61
+ [Size.XS]: 'h-2.5 w-2.5',
62
+ [Size.SM]: 'h-3 w-3',
63
+ [Size.MD]: 'h-4 w-4',
64
+ [Size.LG]: 'h-5 w-5',
65
+ [Size.XL]: 'h-6 w-6',
66
+ [Size.XXL]: 'h-6 w-6'
67
67
  } satisfies Record<VariantSizes, string>
68
68
  )[size]
69
69
  );
@@ -71,12 +71,12 @@
71
71
  const thumbPosition = $derived(
72
72
  (
73
73
  {
74
- [Size.XS]: value ? 'translate-x-3' : 'translate-x-0.5',
75
- [Size.SM]: value ? 'translate-x-3.5' : 'translate-x-0.5',
76
- [Size.MD]: value ? 'translate-x-4' : 'translate-x-0.5',
77
- [Size.LG]: value ? 'translate-x-5' : 'translate-x-0.5',
78
- [Size.XL]: value ? 'translate-x-6' : 'translate-x-0.5',
79
- [Size.XXL]: value ? 'translate-x-6' : 'translate-x-0.5'
74
+ [Size.XS]: value ? 'translate-x-3.5' : 'translate-x-0.5',
75
+ [Size.SM]: value ? 'translate-x-4' : 'translate-x-0.5',
76
+ [Size.MD]: value ? 'translate-x-5' : 'translate-x-0.5',
77
+ [Size.LG]: value ? 'translate-x-6' : 'translate-x-0.5',
78
+ [Size.XL]: value ? 'translate-x-7' : 'translate-x-0.5',
79
+ [Size.XXL]: value ? 'translate-x-7' : 'translate-x-0.5'
80
80
  } satisfies Record<VariantSizes, string>
81
81
  )[size]
82
82
  );
@@ -228,7 +228,8 @@
228
228
 
229
229
  <div
230
230
  class={cn(
231
- 'border-default-200 inline-block rounded-lg border bg-white shadow-xs select-none',
231
+ 'inline-block bg-white select-none',
232
+ 'border-default-200 rounded-lg border shadow-xs',
232
233
  density.panel,
233
234
  density.padding,
234
235
  className
@@ -127,7 +127,14 @@
127
127
  </button>
128
128
 
129
129
  {#snippet content()}
130
- <Calendar {value} {minDate} {maxDate} {size} onselect={(d) => handleSelect(d as Date)} />
130
+ <Calendar
131
+ {value}
132
+ {minDate}
133
+ {maxDate}
134
+ {size}
135
+ class="max-sm:w-full max-sm:rounded-none max-sm:border-0 max-sm:shadow-none"
136
+ onselect={(d) => handleSelect(d as Date)}
137
+ />
131
138
  {/snippet}
132
139
  </Popover>
133
140
 
@@ -236,6 +236,24 @@ export type NumberInputProps = {
236
236
  placeholder?: string;
237
237
  size?: VariantSizes;
238
238
  class?: ClassValue;
239
+ /**
240
+ * Leading icon rendered inside the field. Pass a Svelte component
241
+ * (e.g. an icon from your icon library) to fully customise, or use
242
+ * `iconPreset` for built-in options. When both are set, `icon` wins.
243
+ */
244
+ icon?: Component;
245
+ /**
246
+ * Built-in leading icon preset. Saves importing a separate icon
247
+ * component for common use cases.
248
+ * - `'currency'` — banknotes
249
+ * - `'quantity'` — hash / #
250
+ * - `'percentage'` — %
251
+ * - `'weight'` — scale
252
+ * - `'temperature'` — thermometer
253
+ *
254
+ * Omit (or pass `undefined`) for no icon. Overridden by `icon` prop.
255
+ */
256
+ iconPreset?: 'currency' | 'quantity' | 'percentage' | 'weight' | 'temperature';
239
257
  /**
240
258
  * Currently selected unit. When `units` is provided, this doubles as
241
259
  * the controlled value of the unit dropdown.
@@ -252,6 +270,16 @@ export type NumberInputProps = {
252
270
  dropdownIcon?: Component;
253
271
  /** Fires when the user picks a different unit. */
254
272
  onunitchange?: (prevUnit: string, newUnit: string) => void;
273
+ /**
274
+ * Format large numbers with thousands separators for readability
275
+ * (e.g. `1,232,312`). Formatting is applied on blur; while focused,
276
+ * the raw number is shown so typing stays predictable. @default true
277
+ */
278
+ formatThousands?: boolean;
279
+ /**
280
+ * BCP 47 locale used for thousands-separator formatting. @default 'en-US'
281
+ */
282
+ locale?: string;
255
283
  testId?: string;
256
284
  };
257
285
  /**
@@ -0,0 +1,306 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../helper/cls.js';
3
+ import { buildTestId } from '../../helper/testid.js';
4
+ import { Size } from '../../variants.js';
5
+ import { formSizeTokens } from '../form-size.js';
6
+ import Popover from '../../elements/popover/Popover.svelte';
7
+ import type { MonthPickerProps } from './month-picker-types.js';
8
+
9
+ let {
10
+ name,
11
+ id = name,
12
+ label,
13
+ value = $bindable<Date | null>(null),
14
+ placeholder = 'Select month',
15
+ minDate,
16
+ maxDate,
17
+ clearable = true,
18
+ disabled = false,
19
+ size = Size.MD,
20
+ errors = [],
21
+ class: className = '',
22
+ onselect,
23
+ testId
24
+ }: MonthPickerProps = $props();
25
+
26
+ let open = $state(false);
27
+ let listEl = $state<HTMLDivElement | undefined>();
28
+ const tokens = $derived(formSizeTokens[size]);
29
+ const hasErrors = $derived(errors.length > 0);
30
+
31
+ const MONTH_NAMES = [
32
+ 'January',
33
+ 'February',
34
+ 'March',
35
+ 'April',
36
+ 'May',
37
+ 'June',
38
+ 'July',
39
+ 'August',
40
+ 'September',
41
+ 'October',
42
+ 'November',
43
+ 'December'
44
+ ] as const;
45
+
46
+ const MONTH_SHORT = [
47
+ 'Jan',
48
+ 'Feb',
49
+ 'Mar',
50
+ 'Apr',
51
+ 'May',
52
+ 'Jun',
53
+ 'Jul',
54
+ 'Aug',
55
+ 'Sep',
56
+ 'Oct',
57
+ 'Nov',
58
+ 'Dec'
59
+ ] as const;
60
+
61
+ const display = $derived(value ? `${MONTH_NAMES[value.getMonth()]} ${value.getFullYear()}` : '');
62
+
63
+ // Build a flat list of months spanning a range of years. Default:
64
+ // 5 years before → 5 years after the anchor (selected or today).
65
+ const RANGE_YEARS = 5;
66
+ type MonthEntry = { year: number; month: number; date: Date; label: string; disabled: boolean };
67
+
68
+ const anchor = $derived(value ?? new Date());
69
+ const startYear = $derived(minDate ? minDate.getFullYear() : anchor.getFullYear() - RANGE_YEARS);
70
+ const endYear = $derived(maxDate ? maxDate.getFullYear() : anchor.getFullYear() + RANGE_YEARS);
71
+
72
+ const months = $derived.by<MonthEntry[]>(() => {
73
+ const out: MonthEntry[] = [];
74
+ for (let y = startYear; y <= endYear; y++) {
75
+ for (let m = 0; m < 12; m++) {
76
+ const d = new Date(y, m, 1);
77
+ let disabled = false;
78
+ if (minDate && d < new Date(minDate.getFullYear(), minDate.getMonth(), 1)) disabled = true;
79
+ if (maxDate && d > new Date(maxDate.getFullYear(), maxDate.getMonth(), 1)) disabled = true;
80
+ out.push({
81
+ year: y,
82
+ month: m,
83
+ date: d,
84
+ label: MONTH_NAMES[m],
85
+ disabled
86
+ });
87
+ }
88
+ }
89
+ return out;
90
+ });
91
+
92
+ // Unique sorted years and a fast lookup by year*12+month key.
93
+ const years = $derived([...new Set(months.map((e) => e.year))]);
94
+ const monthMap = $derived(new Map(months.map((e) => [e.year * 12 + e.month, e])));
95
+
96
+ function isSelected(entry: MonthEntry): boolean {
97
+ return !!value && value.getFullYear() === entry.year && value.getMonth() === entry.month;
98
+ }
99
+
100
+ function isCurrent(entry: MonthEntry): boolean {
101
+ const now = new Date();
102
+ return entry.year === now.getFullYear() && entry.month === now.getMonth();
103
+ }
104
+
105
+ function pick(entry: MonthEntry) {
106
+ if (entry.disabled) return;
107
+ value = entry.date;
108
+ onselect?.(entry.date);
109
+ open = false;
110
+ }
111
+
112
+ function clear(e: MouseEvent) {
113
+ e.stopPropagation();
114
+ value = null;
115
+ open = false;
116
+ onselect?.(null);
117
+ }
118
+
119
+ function setThisMonth() {
120
+ const now = new Date();
121
+ const d = new Date(now.getFullYear(), now.getMonth(), 1);
122
+ if (minDate && d < new Date(minDate.getFullYear(), minDate.getMonth(), 1)) return;
123
+ if (maxDate && d > new Date(maxDate.getFullYear(), maxDate.getMonth(), 1)) return;
124
+ value = d;
125
+ onselect?.(value);
126
+ open = false;
127
+ }
128
+
129
+ // Auto-scroll to the selected (or current) month when the panel opens.
130
+ $effect(() => {
131
+ if (!open || !listEl) return;
132
+ requestAnimationFrame(() => {
133
+ const target =
134
+ listEl?.querySelector('[data-selected="true"]') ??
135
+ listEl?.querySelector('[data-current="true"]');
136
+ target?.scrollIntoView({ block: 'center' });
137
+ });
138
+ });
139
+ </script>
140
+
141
+ <div class={cn('w-full', className)}>
142
+ {#if label}
143
+ <label for={id} class="text-default-700 mb-1 block text-sm font-medium">
144
+ {label}
145
+ </label>
146
+ {/if}
147
+
148
+ <input
149
+ type="hidden"
150
+ {name}
151
+ value={value ? `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}` : ''}
152
+ />
153
+
154
+ <Popover trigger="manual" bind:open placement="bottom" {disabled}>
155
+ <button
156
+ {id}
157
+ type="button"
158
+ {disabled}
159
+ onclick={() => {
160
+ if (!disabled) open = !open;
161
+ }}
162
+ aria-haspopup="dialog"
163
+ aria-expanded={open}
164
+ class={cn(
165
+ 'flex w-full items-center border bg-white transition-colors',
166
+ 'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
167
+ tokens.height,
168
+ tokens.padX,
169
+ tokens.text,
170
+ tokens.gap,
171
+ tokens.radius,
172
+ tokens.shadow,
173
+ hasErrors
174
+ ? 'border-danger-300 focus-visible:border-danger-500 focus-visible:ring-danger-500'
175
+ : 'border-default-300 focus-visible:border-primary-500 focus-visible:ring-primary-500',
176
+ disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
177
+ )}
178
+ data-testid={buildTestId('month-picker', undefined, testId)}
179
+ >
180
+ <span class={cn('flex-1 text-left', !display && 'text-default-400')}>
181
+ {display || placeholder}
182
+ </span>
183
+ {#if clearable && value && !disabled}
184
+ <span
185
+ role="button"
186
+ tabindex="-1"
187
+ onclick={clear}
188
+ onkeydown={(e) => {
189
+ if (e.key === 'Enter') clear(e as unknown as MouseEvent);
190
+ }}
191
+ aria-label="Clear month"
192
+ class={cn(
193
+ 'text-default-400 hover:text-default-700 flex cursor-pointer items-center justify-center rounded',
194
+ tokens.iconSize
195
+ )}
196
+ >
197
+ <svg class="size-3" viewBox="0 0 12 12" fill="none" aria-hidden="true">
198
+ <path
199
+ d="M3 3l6 6M9 3l-6 6"
200
+ stroke="currentColor"
201
+ stroke-width="1.5"
202
+ stroke-linecap="round"
203
+ />
204
+ </svg>
205
+ </span>
206
+ {/if}
207
+ <svg
208
+ class={cn('text-default-400', tokens.iconSize)}
209
+ viewBox="0 0 20 20"
210
+ fill="currentColor"
211
+ aria-hidden="true"
212
+ >
213
+ <path
214
+ fill-rule="evenodd"
215
+ d="M5.75 2a.75.75 0 0 1 .75.75V4h7V2.75a.75.75 0 0 1 1.5 0V4h.25A2.75 2.75 0 0 1 18 6.75v8.5A2.75 2.75 0 0 1 15.25 18H4.75A2.75 2.75 0 0 1 2 15.25v-8.5A2.75 2.75 0 0 1 4.75 4H5V2.75A.75.75 0 0 1 5.75 2zM4.75 5.5c-.69 0-1.25.56-1.25 1.25V8h13V6.75c0-.69-.56-1.25-1.25-1.25H4.75zM16.5 9.5h-13v5.75c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25V9.5z"
216
+ clip-rule="evenodd"
217
+ />
218
+ </svg>
219
+ </button>
220
+
221
+ {#snippet content({ close })}
222
+ {@render monthGrid(close)}
223
+ {/snippet}
224
+ </Popover>
225
+
226
+ {#if hasErrors}
227
+ <ul class="mt-1 space-y-0.5" role="alert">
228
+ {#each errors as error (error)}
229
+ <li class="text-danger-600 text-xs">{error}</li>
230
+ {/each}
231
+ </ul>
232
+ {/if}
233
+ </div>
234
+
235
+ {#snippet monthGrid(close: () => void)}
236
+ <div class="flex w-full flex-col sm:w-56">
237
+ <div
238
+ bind:this={listEl}
239
+ class="max-h-72 overflow-y-auto [scrollbar-width:none] sm:max-h-72 [&::-webkit-scrollbar]:hidden"
240
+ >
241
+ {#each years as year (year)}
242
+ {@const yearSelected = value?.getFullYear() === year}
243
+ <div
244
+ class={cn(
245
+ 'border-default-200 sticky top-0 z-10 border-b px-3 py-1.5 text-xs font-bold',
246
+ yearSelected ? 'bg-primary-50 text-primary-700' : 'bg-default-50 text-default-800'
247
+ )}
248
+ data-year={year}
249
+ >
250
+ {year}
251
+ </div>
252
+ <div class="grid grid-cols-4 gap-0.5 p-1.5">
253
+ {#each MONTH_SHORT as monthLabel, m (m)}
254
+ {@const entry = monthMap.get(year * 12 + m)}
255
+ {@const sel = entry ? isSelected(entry) : false}
256
+ {@const cur = entry ? isCurrent(entry) : false}
257
+ {@const dis = entry?.disabled ?? true}
258
+ <button
259
+ type="button"
260
+ data-month={m}
261
+ data-selected={sel || undefined}
262
+ data-current={cur || undefined}
263
+ onclick={() => entry && pick(entry)}
264
+ disabled={dis}
265
+ class={cn(
266
+ 'cursor-pointer rounded px-1 py-2 text-xs font-medium transition-colors sm:py-1',
267
+ sel
268
+ ? 'bg-primary-500 text-white'
269
+ : cur
270
+ ? 'text-primary-600 bg-primary-50 ring-primary-300 ring-1'
271
+ : 'text-default-600 hover:bg-default-100',
272
+ dis && 'text-default-300 cursor-not-allowed'
273
+ )}
274
+ >
275
+ {monthLabel}
276
+ </button>
277
+ {/each}
278
+ </div>
279
+ {/each}
280
+ </div>
281
+
282
+ <div class="border-default-200 flex items-center justify-between border-t px-3 py-2">
283
+ {#if clearable}
284
+ <button
285
+ type="button"
286
+ onclick={(e) => {
287
+ clear(e);
288
+ close();
289
+ }}
290
+ class="text-primary-600 cursor-pointer text-xs font-medium hover:underline"
291
+ >
292
+ Clear
293
+ </button>
294
+ {:else}
295
+ <span></span>
296
+ {/if}
297
+ <button
298
+ type="button"
299
+ onclick={setThisMonth}
300
+ class="text-primary-600 cursor-pointer text-xs font-medium hover:underline"
301
+ >
302
+ This month
303
+ </button>
304
+ </div>
305
+ </div>
306
+ {/snippet}
@@ -0,0 +1,4 @@
1
+ import type { MonthPickerProps } from './month-picker-types.js';
2
+ declare const MonthPicker: import("svelte").Component<MonthPickerProps, {}, "value">;
3
+ type MonthPicker = ReturnType<typeof MonthPicker>;
4
+ export default MonthPicker;
@@ -0,0 +1,22 @@
1
+ import type { ClassValue } from 'tailwind-variants';
2
+ import type { VariantSizes } from '../../index.js';
3
+ export type MonthPickerProps = {
4
+ name: string;
5
+ id?: string;
6
+ label?: string;
7
+ /** Bindable selected month. Always the 1st of the month, or null. */
8
+ value?: Date | null;
9
+ placeholder?: string;
10
+ /** Earliest selectable month (inclusive, day is ignored). */
11
+ minDate?: Date;
12
+ /** Latest selectable month (inclusive, day is ignored). */
13
+ maxDate?: Date;
14
+ /** Show a × to clear the selection. @default true */
15
+ clearable?: boolean;
16
+ disabled?: boolean;
17
+ size?: VariantSizes;
18
+ errors?: string[];
19
+ class?: ClassValue;
20
+ onselect?: (value: Date | null) => void;
21
+ testId?: string;
22
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -12,7 +12,7 @@ export declare const segmentedTrack: import("tailwind-variants").TVReturnType<{
12
12
  vertical: string;
13
13
  auto: string;
14
14
  };
15
- }, undefined, "inline-flex max-w-full overflow-x-auto rounded-lg border [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", {
15
+ }, undefined, "flex max-w-full overflow-x-auto rounded-lg border sm:inline-flex [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", {
16
16
  appearance: {
17
17
  surface: string;
18
18
  inverted: string;
@@ -34,7 +34,7 @@ export declare const segmentedTrack: import("tailwind-variants").TVReturnType<{
34
34
  vertical: string;
35
35
  auto: string;
36
36
  };
37
- }, undefined, "inline-flex max-w-full overflow-x-auto rounded-lg border [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", unknown, unknown, undefined>>;
37
+ }, undefined, "flex max-w-full overflow-x-auto rounded-lg border sm:inline-flex [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", unknown, unknown, undefined>>;
38
38
  export declare function segmentClasses(args: {
39
39
  selected: boolean;
40
40
  disabled: boolean;
@@ -3,9 +3,11 @@ import { cn } from '../helper/cls.js';
3
3
  import { Color } from '../variants.js';
4
4
  import { formSizeTokens } from './form-size.js';
5
5
  export const segmentedTrack = tv({
6
- // `max-w-full overflow-x-auto` + hidden scrollbar lets a long segment
7
- // row swipe on narrow viewports instead of bleeding past the parent.
8
- base: 'inline-flex max-w-full overflow-x-auto rounded-lg border [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
6
+ // Below `sm`, take full width so the control fills its container on
7
+ // mobile. Above `sm`, shrink to content via `inline-flex`. Either
8
+ // way, `overflow-x-auto` + hidden scrollbar lets a long segment row
9
+ // swipe horizontally without a visible bar.
10
+ base: 'flex max-w-full overflow-x-auto rounded-lg border sm:inline-flex [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
9
11
  variants: {
10
12
  appearance: {
11
13
  surface: 'border-default-200 bg-white p-0',
@@ -48,14 +50,14 @@ function segmentSize(size) {
48
50
  export function segmentClasses(args) {
49
51
  const { selected, disabled, appearance, color, size } = args;
50
52
  if (appearance === 'pills') {
51
- const pillBase = cn('flex cursor-pointer items-center justify-center rounded-full font-medium transition-colors duration-150 shrink-0 whitespace-nowrap', 'focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-offset-2', segmentSize(size), disabled && 'cursor-not-allowed opacity-50');
53
+ const pillBase = cn('flex cursor-pointer items-center justify-center rounded-full font-medium transition-colors duration-150 flex-1 whitespace-nowrap sm:flex-initial sm:shrink-0', 'focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-offset-2', segmentSize(size), disabled && 'cursor-not-allowed opacity-50');
52
54
  if (disabled)
53
55
  return cn(pillBase, 'text-default-400');
54
56
  if (selected)
55
57
  return cn(pillBase, selectedByColor[color]);
56
58
  return cn(pillBase, 'bg-default-100 text-default-700 hover:bg-default-200');
57
59
  }
58
- const base = cn('flex cursor-pointer items-center justify-center font-medium transition-colors duration-150 shrink-0 whitespace-nowrap', 'focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none', appearance === 'inverted' ? 'focus-visible:ring-offset-0' : 'focus-visible:ring-offset-2',
60
+ const base = cn('flex cursor-pointer items-center justify-center font-medium transition-colors duration-150 flex-1 whitespace-nowrap sm:flex-initial sm:shrink-0', 'focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none', appearance === 'inverted' ? 'focus-visible:ring-offset-0' : 'focus-visible:ring-offset-2',
59
61
  // Inverted track has p-0.5 padding around segments — give them inner radius
60
62
  // so selected segments don't render as square boxes (matches surface look).
61
63
  appearance === 'inverted' && 'rounded-md', segmentSize(size), disabled && 'cursor-not-allowed opacity-50');
package/dist/index.d.ts CHANGED
@@ -51,6 +51,7 @@ export type { TooltipProps, TooltipPlacement, TooltipSize, TooltipVariant } from
51
51
  export type { PopoverProps, PopoverPlacement, PopoverTrigger } from './elements/popover/popover-types.js';
52
52
  export type { CalendarProps, CalendarMode } from './forms/calendar/calendar-types.js';
53
53
  export type { DatePickerProps } from './forms/date-picker/date-picker-types.js';
54
+ export type { MonthPickerProps } from './forms/month-picker/month-picker-types.js';
54
55
  export type { ComboBoxProps, ComboBoxItem } from './elements/combobox/combobox-types.js';
55
56
  export type { ContextMenuProps, ContextMenuItem } from './elements/context-menu/context-menu-types.js';
56
57
  export type { AccordionProps } from './elements/accordion/accordion-types.js';
@@ -124,6 +125,7 @@ export { default as NumberInput } from './forms/NumberInput.svelte';
124
125
  export { default as DateRange } from './forms/DateRange.svelte';
125
126
  export { default as Calendar } from './forms/calendar/Calendar.svelte';
126
127
  export { default as DatePicker } from './forms/date-picker/DatePicker.svelte';
128
+ export { default as MonthPicker } from './forms/month-picker/MonthPicker.svelte';
127
129
  export { default as Tags } from './forms/Tags.svelte';
128
130
  export { default as SegmentedControl } from './forms/SegmentedControl.svelte';
129
131
  export { default as MarketSelector } from './forms/MarketSelector.svelte';
package/dist/index.js CHANGED
@@ -112,6 +112,7 @@ export { default as NumberInput } from './forms/NumberInput.svelte';
112
112
  export { default as DateRange } from './forms/DateRange.svelte';
113
113
  export { default as Calendar } from './forms/calendar/Calendar.svelte';
114
114
  export { default as DatePicker } from './forms/date-picker/DatePicker.svelte';
115
+ export { default as MonthPicker } from './forms/month-picker/MonthPicker.svelte';
115
116
  export { default as Tags } from './forms/Tags.svelte';
116
117
  export { default as SegmentedControl } from './forms/SegmentedControl.svelte';
117
118
  export { default as MarketSelector } from './forms/MarketSelector.svelte';
@@ -115,7 +115,7 @@
115
115
  <div class="mb-1 flex justify-between gap-x-4">
116
116
  <div class="flex flex-wrap items-center gap-2">
117
117
  <button
118
- class="text-default-900 text-sm font-medium"
118
+ class="text-default-900 cursor-pointer text-sm font-medium"
119
119
  onclick={() => onitemclick?.(activityItem, index)}
120
120
  >
121
121
  {activityItem.title}
@@ -2,11 +2,11 @@ import { tv } from 'tailwind-variants';
2
2
  import { Size } from '../index.js';
3
3
  export const modal = tv({
4
4
  slots: {
5
- base: 'fixed inset-0 z-50 flex items-center justify-center p-4',
5
+ base: 'fixed inset-0 z-50 flex items-center justify-center p-2 sm:p-4',
6
6
  backdrop: 'fixed inset-0 bg-black/50 backdrop-blur-sm',
7
- container: 'relative w-full flex flex-col bg-white rounded-xl shadow-2xl',
8
- header: 'px-6 py-4 border-b border-default-200 flex items-center justify-between shrink-0',
9
- body: 'flex-1 px-6 py-4 overflow-y-auto',
7
+ container: 'relative w-full flex flex-col bg-white rounded-xl shadow-2xl max-sm:max-w-none max-sm:max-h-[95vh]',
8
+ header: 'px-4 py-3 sm:px-6 sm:py-4 border-b border-default-200 flex items-center justify-between shrink-0',
9
+ body: 'flex-1 px-4 py-3 sm:px-6 sm:py-4 overflow-y-auto',
10
10
  footer: 'bg-default-50/80 rounded-b-xl shrink-0',
11
11
  title: 'text-lg font-semibold text-default-900',
12
12
  description: 'text-sm text-default-600 mt-1',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makolabs/ripple",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Simple Svelte 5 powered component library ✨",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {