@makolabs/ripple 3.0.2 → 3.0.4

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 (37) hide show
  1. package/dist/ai/ai-types.d.ts +7 -0
  2. package/dist/charts/Chart.svelte +18 -37
  3. package/dist/charts/chart-types.d.ts +7 -0
  4. package/dist/drawer/Drawer.svelte +29 -36
  5. package/dist/drawer/drawer.js +2 -2
  6. package/dist/elements/combobox/ComboBox.svelte +6 -6
  7. package/dist/elements/dropdown/Select.svelte +6 -8
  8. package/dist/elements/popover/Popover.svelte +1 -1
  9. package/dist/elements/progress/Progress.svelte +18 -5
  10. package/dist/elements/progress/progress-types.d.ts +8 -0
  11. package/dist/file-browser/FileBrowser.svelte +6 -3
  12. package/dist/filters/CompactFilters.svelte +78 -68
  13. package/dist/filters/filter-types.d.ts +11 -0
  14. package/dist/forms/DateRange.svelte +31 -20
  15. package/dist/forms/NumberInput.svelte +6 -2
  16. package/dist/forms/Tags.svelte +9 -4
  17. package/dist/forms/Toggle.svelte +8 -6
  18. package/dist/forms/calendar/Calendar.svelte +8 -2
  19. package/dist/forms/calendar/calendar-types.d.ts +9 -0
  20. package/dist/forms/date-picker/DatePicker.svelte +8 -1
  21. package/dist/forms/form-types.d.ts +23 -0
  22. package/dist/forms/month-picker/MonthPicker.svelte +12 -3
  23. package/dist/forms/month-picker/month-picker-types.d.ts +7 -0
  24. package/dist/header/Breadcrumbs.svelte +19 -5
  25. package/dist/header/header-types.d.ts +7 -0
  26. package/dist/layout/activity-list/ActivityList.svelte +29 -7
  27. package/dist/layout/activity-list/activity-list-types.d.ts +8 -0
  28. package/dist/layout/card/MetricCard.svelte +34 -8
  29. package/dist/layout/card/RankedCard.svelte +34 -10
  30. package/dist/layout/card/card-types.d.ts +8 -0
  31. package/dist/layout/card/ranked-card.d.ts +10 -0
  32. package/dist/layout/table/Table.svelte +5 -0
  33. package/dist/layout/table/table-types.d.ts +8 -0
  34. package/dist/modal/modal.js +4 -4
  35. package/dist/pipeline/Pipeline.svelte +7 -3
  36. package/dist/pipeline/pipeline-types.d.ts +6 -0
  37. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../helper/cls.js';
3
+ import { buildTestId } from '../../helper/testid.js';
3
4
  import { metricCard } from './metric-card.js';
4
5
  import type { MetricCardProps } from '../../index.js';
5
6
  import Progress from '../../elements/progress/Progress.svelte';
@@ -16,7 +17,8 @@
16
17
  onclick,
17
18
  action,
18
19
  actionHover,
19
- loading = false
20
+ loading = false,
21
+ testId
20
22
  }: MetricCardProps = $props();
21
23
 
22
24
  const interactive = $derived(!!onclick);
@@ -54,6 +56,7 @@
54
56
  <span
55
57
  class={cn(actionSlot(), hasHoverSwap && 'group-hover:opacity-0')}
56
58
  data-metric-card-action=""
59
+ data-testid={buildTestId('metric-card', 'action', testId)}
57
60
  aria-hidden="true"
58
61
  >
59
62
  {#if action}
@@ -90,17 +93,24 @@
90
93
  </div>
91
94
  {:else}
92
95
  {#if title}
93
- <div class={titleSlot()}>{title}</div>
96
+ <div class={titleSlot()} data-testid={buildTestId('metric-card', 'label', testId)}>
97
+ {title}
98
+ </div>
94
99
  {/if}
95
100
 
96
101
  {#if value !== undefined}
97
- <div class={valueSlot()}>{value}</div>
102
+ <div class={valueSlot()} data-testid={buildTestId('metric-card', 'value', testId)}>
103
+ {value}
104
+ </div>
98
105
  {/if}
99
106
 
100
107
  {#if details.length > 0}
101
108
  <div class={detailSlot()}>
102
109
  {#each details as detail, index (detail.label + index)}
103
- <div class="flex justify-between text-xs">
110
+ <div
111
+ class="flex justify-between text-xs"
112
+ data-testid={buildTestId('metric-card', 'detail', testId, index)}
113
+ >
104
114
  <span class="text-default-500">{detail.label}</span>
105
115
  <span class="font-medium {detail.color || 'text-default-900'}">{detail.value}</span>
106
116
  </div>
@@ -109,7 +119,10 @@
109
119
  {/if}
110
120
 
111
121
  {#if segments}
112
- <div class={cn(progressSlot(), 'pt-2')}>
122
+ <div
123
+ class={cn(progressSlot(), 'pt-2')}
124
+ data-testid={buildTestId('metric-card', 'trend', testId)}
125
+ >
113
126
  <Progress
114
127
  value={0}
115
128
  {segments}
@@ -120,7 +133,10 @@
120
133
  />
121
134
  </div>
122
135
  {:else if percent !== undefined}
123
- <div class={cn(progressSlot(), 'pt-2')}>
136
+ <div
137
+ class={cn(progressSlot(), 'pt-2')}
138
+ data-testid={buildTestId('metric-card', 'trend', testId)}
139
+ >
124
140
  <Progress value={percent} size={Size.SM} color={Color.SUCCESS} showLabel={false} />
125
141
  </div>
126
142
  {/if}
@@ -128,11 +144,21 @@
128
144
  {/snippet}
129
145
 
130
146
  {#if interactive}
131
- <button type="button" class={baseClass} data-metric-card="" onclick={handleClick}>
147
+ <button
148
+ type="button"
149
+ class={baseClass}
150
+ data-metric-card=""
151
+ data-testid={buildTestId('metric-card', undefined, testId)}
152
+ onclick={handleClick}
153
+ >
132
154
  {@render body()}
133
155
  </button>
134
156
  {:else}
135
- <div class={baseClass} data-metric-card="">
157
+ <div
158
+ class={baseClass}
159
+ data-metric-card=""
160
+ data-testid={buildTestId('metric-card', undefined, testId)}
161
+ >
136
162
  {@render body()}
137
163
  </div>
138
164
  {/if}
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../helper/cls.js';
3
+ import { buildTestId } from '../../helper/testid.js';
3
4
  import { rankedCard, type RankedCardProps } from './ranked-card.js';
4
5
 
5
- let { items, columns = 3, class: className = '' }: RankedCardProps = $props();
6
+ let { items, columns = 3, class: className = '', testId }: RankedCardProps = $props();
6
7
 
7
8
  const {
8
9
  container,
@@ -22,28 +23,51 @@
22
23
  const containerClass = $derived(cn(container(), className));
23
24
  </script>
24
25
 
25
- <div class={containerClass}>
26
- {#each items as item (item.rank)}
27
- <div class={card()}>
26
+ <div class={containerClass} data-testid={buildTestId('ranked-card', undefined, testId)}>
27
+ {#each items as item, index (item.rank)}
28
+ <div class={card()} data-testid={buildTestId('ranked-card', 'card', testId, index)}>
28
29
  <!-- Header with Rank and Title -->
29
30
  <div class={header()}>
30
- <span class={rank()}>#{item.rank}</span>
31
- <h4 class={title()}>{item.title}</h4>
31
+ <span class={rank()} data-testid={buildTestId('ranked-card', 'rank', testId, index)}
32
+ >#{item.rank}</span
33
+ >
34
+ <h4 class={title()} data-testid={buildTestId('ranked-card', 'title', testId, index)}>
35
+ {item.title}
36
+ </h4>
32
37
  </div>
33
38
 
34
39
  <!-- Metrics -->
35
40
  <div class={metricsContainer()}>
36
- {#each item.metrics as metric (metric.label)}
41
+ {#each item.metrics as metric, metricIndex (metric.label)}
37
42
  <div class={metricRow()}>
38
- <span class={metricLabel()}>{metric.label}:</span>
39
- <span class={cn(metricValue(), metric.color || '')}>{metric.value}</span>
43
+ <span
44
+ class={metricLabel()}
45
+ data-testid={buildTestId(
46
+ 'ranked-card',
47
+ 'metric-label',
48
+ testId,
49
+ `${index}-${metricIndex}`
50
+ )}>{metric.label}:</span
51
+ >
52
+ <span
53
+ class={cn(metricValue(), metric.color || '')}
54
+ data-testid={buildTestId(
55
+ 'ranked-card',
56
+ 'metric-value',
57
+ testId,
58
+ `${index}-${metricIndex}`
59
+ )}>{metric.value}</span
60
+ >
40
61
  </div>
41
62
  {/each}
42
63
  </div>
43
64
 
44
65
  <!-- Action/Recommendation -->
45
66
  {#if item.action}
46
- <div class={actionContainer()}>
67
+ <div
68
+ class={actionContainer()}
69
+ data-testid={buildTestId('ranked-card', 'action', testId, index)}
70
+ >
47
71
  <p class={actionText()}>
48
72
  <span class={actionLabel()}>Action:</span>
49
73
  <span class={item.action.color || ''}>{item.action.text}</span>
@@ -168,5 +168,13 @@ export type MetricCardProps = {
168
168
  * data is loading. @default false
169
169
  */
170
170
  loading?: boolean;
171
+ /**
172
+ * Test ID prefix. When set, the component emits these selectors:
173
+ * - `{testId}-metric-card` — root wrapper
174
+ * - `{testId}-metric-card-value` — big number
175
+ * - `{testId}-metric-card-label` — label text
176
+ * - `{testId}-metric-card-detail-{i}` — each detail row
177
+ * - `{testId}-metric-card-action` — action area
178
+ */
171
179
  testId?: string;
172
180
  };
@@ -102,4 +102,14 @@ export type RankedCardProps = {
102
102
  items: RankedCardItem[];
103
103
  columns?: 1 | 2 | 3 | 4;
104
104
  class?: ClassValue;
105
+ /**
106
+ * Test ID prefix. When set, the component emits these selectors:
107
+ * - `{testId}-ranked-card` — root wrapper
108
+ * - `{testId}-ranked-card-item-{i}` — each card
109
+ * - `{testId}-ranked-card-rank-{i}` — rank number
110
+ * - `{testId}-ranked-card-title-{i}` — title
111
+ * - `{testId}-ranked-card-metric-label-{i}-{j}` — metric label
112
+ * - `{testId}-ranked-card-metric-value-{i}-{j}` — metric value
113
+ */
114
+ testId?: string;
105
115
  };
@@ -622,3 +622,8 @@
622
622
  {:else}
623
623
  {@render tableContent()}
624
624
  {/if}
625
+ {#if testId}
626
+ <div data-testid={buildTestId('table', 'data', testId)} style="display:none" aria-hidden="true">
627
+ {JSON.stringify(getPaginatedData())}
628
+ </div>
629
+ {/if}
@@ -202,5 +202,13 @@ export type TableProps<T = DataRow> = {
202
202
  rowKey?: string;
203
203
  /** Allow rows to expand/collapse showing `expandedContent`. @default false */
204
204
  expandable?: boolean;
205
+ /**
206
+ * Test ID prefix. When set, the component emits these selectors:
207
+ * - `{testId}-table` — root table element
208
+ * - `{testId}-table-head` — thead
209
+ * - `{testId}-table-data` — hidden element containing the current
210
+ * page's row data as JSON, so test automation can read values
211
+ * without parsing individual cells
212
+ */
205
213
  testId?: string;
206
214
  };
@@ -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',
@@ -11,7 +11,7 @@
11
11
  class: className = '',
12
12
  size = 'md',
13
13
  equalWidth = true,
14
- chevronGap = 0,
14
+ chevronGap = 4,
15
15
  selectedClass,
16
16
  unselectedClass,
17
17
  disabledClass,
@@ -74,9 +74,13 @@
74
74
  {#if children}
75
75
  {@render children(stage, index)}
76
76
  {:else}
77
- <span class={s.label()}>{stage.label}</span>
77
+ <span class={s.label()} data-testid={buildTestId('pipeline', 'label', testId, index)}
78
+ >{stage.label}</span
79
+ >
78
80
  {#if stage.count !== undefined}
79
- <span class={s.count()}>{stage.count}</span>
81
+ <span class={s.count()} data-testid={buildTestId('pipeline', 'count', testId, index)}
82
+ >{stage.count}</span
83
+ >
80
84
  {/if}
81
85
  {/if}
82
86
  </div>
@@ -86,5 +86,11 @@ export type PipelineProps = {
86
86
  onstagehover?: (e: PipelineStagePointerEvent) => void;
87
87
  /** Fires on stage mouseleave. */
88
88
  onstageleave?: (e: PipelineStagePointerEvent) => void;
89
+ /**
90
+ * Test ID prefix. When set, the component emits these selectors:
91
+ * - `{testId}-pipeline` — root wrapper
92
+ * - `{testId}-pipeline-label-{i}` — stage label
93
+ * - `{testId}-pipeline-count-{i}` — stage count
94
+ */
89
95
  testId?: string;
90
96
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makolabs/ripple",
3
- "version": "3.0.2",
3
+ "version": "3.0.4",
4
4
  "description": "Simple Svelte 5 powered component library ✨",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {