@imaginario27/air-ui-ds 1.17.0 → 1.17.2

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/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ All notable changes to this package are documented in this file.
5
5
  Historical releases were reconstructed from git history (GitHub repository) and npm publish dates.
6
6
  Future releases will include detailed entries generated with Changesets.
7
7
 
8
+ ## 1.17.0 - 2026-07-14
9
+
10
+ Release type: minor.
11
+ Commits found in range: 2.
12
+
13
+ ### Added
14
+
15
+ 1. expand RepeaterField into a full-featured form field ([0380511](https://github.com/imaginario27/air-ui/commit/038051135acd113e040f3183db7cc542e2e00bf9))
16
+ 2. add row reordering to RulesField via new DragPlaceholder ([a966db6](https://github.com/imaginario27/air-ui/commit/a966db6c30346d5912bc1fa037a20239c07c6af9))
17
+
18
+ - Package: @imaginario27/air-ui-ds.
19
+
20
+ ## 1.16.0 - 2026-07-07
21
+
22
+ Release type: minor.
23
+ Commits found in range: 1.
24
+
25
+ ### Added
26
+
27
+ 1. extract standalone Switch component and polish interaction transitions ([4c28c2d](https://github.com/imaginario27/air-ui/commit/4c28c2d34dc07f299f100e3badc491d67ebf8ca4))
28
+
29
+ - Package: @imaginario27/air-ui-ds.
30
+
8
31
  ## 1.15.3 - 2026-07-03
9
32
 
10
33
  Release type: patch.
@@ -4,13 +4,14 @@
4
4
  :class="[
5
5
  'w-full',
6
6
  'flex gap-3',
7
- description === undefined || description === '' ? 'px-4 py-2' : 'p-4',
7
+ description || $slots.description ? 'p-4' : 'px-4 py-2',
8
8
  'rounded-lg',
9
9
  'border',
10
10
  containerClass,
11
+ 'relative',
11
12
  ]"
12
13
  >
13
- <template v-if="description">
14
+ <template v-if="description || $slots.description">
14
15
  <Icon
15
16
  :name="iconType"
16
17
  :iconClass="iconColorClass"
@@ -26,10 +27,17 @@
26
27
  >
27
28
  {{ title }}
28
29
  </span>
29
- <p v-html="description" class="text-sm" />
30
+
31
+ <slot name="description" />
32
+
33
+ <p
34
+ v-if="!$slots.description && description"
35
+ v-html="description"
36
+ class="text-sm"
37
+ />
30
38
 
31
39
  <div
32
- v-if="buttons?.length"
40
+ v-if="hasActionButtons && buttons?.length"
33
41
  class="flex gap-6"
34
42
  >
35
43
  <AlertButton
@@ -45,11 +53,26 @@
45
53
  />
46
54
  </div>
47
55
  </div>
56
+
57
+ <AlertIconButton
58
+ v-if="hasCloseButton"
59
+ :type
60
+ icon="mdi:close"
61
+ class="absolute right-2 top-2"
62
+ @click="$emit('close')"
63
+ />
48
64
  </template>
49
65
 
50
66
  <template v-else>
51
67
  <div class="w-full flex gap-3">
52
- <div class="w-full flex gap-3 pt-1.5">
68
+ <div
69
+ :class="[
70
+ 'w-full',
71
+ 'flex',
72
+ 'gap-3',
73
+ hasCloseButton || (hasActionButtons && buttons?.length) && 'pt-1.5',
74
+ ]"
75
+ >
53
76
  <Icon
54
77
  :name="iconType"
55
78
  :iconClass="iconColorClass"
@@ -61,7 +84,7 @@
61
84
 
62
85
  <div class="flex gap-3">
63
86
  <div
64
- v-if="buttons?.length"
87
+ v-if="hasActionButtons && buttons?.length"
65
88
  class="flex gap-4"
66
89
  >
67
90
  <AlertButton
@@ -103,10 +126,14 @@ const props = defineProps({
103
126
  default: 'Title',
104
127
  },
105
128
  description: String as PropType<string>,
129
+ hasActionButtons: {
130
+ type: Boolean as PropType<boolean>,
131
+ default: false
132
+ },
106
133
  buttons: Array as PropType<AlertButton[]>,
107
134
  hasCloseButton: {
108
135
  type: Boolean as PropType<boolean>,
109
- default: true,
136
+ default: false,
110
137
  },
111
138
  })
112
139
 
@@ -153,5 +180,4 @@ const iconType = computed(() => {
153
180
  }
154
181
  return variant[props.type as AlertType] as string || 'mdi:alert-outline'
155
182
  })
156
-
157
183
  </script>
@@ -60,6 +60,10 @@
60
60
  :shape="containedIconShape"
61
61
  />
62
62
  </template>
63
+
64
+ <template v-if="iconPosition === MetricCardIconPosition.LEFT && $slots.rightTop">
65
+ <slot name="rightTop" />
66
+ </template>
63
67
  </CardHeader>
64
68
  <CardBody :class="['flex', 'gap-2!', cardBodyClass]">
65
69
  <div :class="['flex', 'items-end', 'gap-1', textColorClass]">
@@ -104,6 +108,13 @@
104
108
  {{ trend }}
105
109
  </span>
106
110
  </div>
111
+
112
+ <div
113
+ v-if="$slots.footer"
114
+ class="w-full flex gap-2 mt-2"
115
+ >
116
+ <slot name="footer" />
117
+ </div>
107
118
  </CardBody>
108
119
  </Card>
109
120
  </template>
@@ -184,6 +184,23 @@
184
184
  </div>
185
185
  </div>
186
186
  </template>
187
+
188
+ <!-- Trailing drop zone: lets an item be dragged into the last position -->
189
+ <div
190
+ v-if="sortingType === RepeatingFieldSortingType.DRAG && draggedIndex !== null && draggedIndex !== items.length - 1"
191
+ @dragover.prevent="handleDragOver(items.length, $event)"
192
+ @drop.prevent="handleDrop(items.length, $event)"
193
+ >
194
+ <DragPlaceholder
195
+ v-if="dragOverIndex === items.length"
196
+ aria-hidden="true"
197
+ :text="dragPlaceholderText"
198
+ :showText="showDragPlaceholderText"
199
+ :textClass="dragPlaceholderTextClass"
200
+ :class="['h-10', dragPlaceholderClass]"
201
+ />
202
+ <div v-else class="h-4" />
203
+ </div>
187
204
  </div>
188
205
 
189
206
  <!-- Help Text (bottom) -->
@@ -348,8 +348,6 @@ const normalizeRules = (list: RuleItem[]): RuleItem[] => {
348
348
  return list.length ? cloneRules(list) : [createEmptyRule()]
349
349
  }
350
350
 
351
- // Local draft state: edits to item/operator/value only sync to the parent
352
- // via emit on add, remove, or Enter — not on every keystroke/selection.
353
351
  const localRules = ref<RuleItem[]>(normalizeRules(props.modelValue))
354
352
 
355
353
  watch(
@@ -454,7 +452,7 @@ const resolveRuleTypeFromItem = (itemValue: RuleValue): AllowedInputType => {
454
452
  }
455
453
 
456
454
  const updateRule = (index: number, field: keyof RuleItem, value: RuleValue) => {
457
- localRules.value = localRules.value.map((rule, currentIndex) => {
455
+ const nextRules = localRules.value.map((rule, currentIndex) => {
458
456
  if (currentIndex !== index) return rule
459
457
 
460
458
  if (field === 'item') {
@@ -471,6 +469,14 @@ const updateRule = (index: number, field: keyof RuleItem, value: RuleValue) => {
471
469
  [field]: value,
472
470
  }
473
471
  })
472
+
473
+ localRules.value = nextRules
474
+
475
+ // The trailing row is the not-yet-added draft rule; only commit to the
476
+ // model once it's confirmed via the add action (button, +, or Enter).
477
+ if (index !== nextRules.length - 1) {
478
+ emit('update:modelValue', nextRules)
479
+ }
474
480
  }
475
481
 
476
482
  const addRule = () => {
@@ -571,7 +577,9 @@ const handleDragOver = (index: number, event: DragEvent) => {
571
577
 
572
578
  event.preventDefault()
573
579
 
574
- if (!isSortableRow(index)) {
580
+ // The add-row (last index) isn't itself sortable, but hovering it means
581
+ // "drop after the last sortable rule" — allow that position through.
582
+ if (!isSortableRow(index) && index !== rules.value.length - 1) {
575
583
  return
576
584
  }
577
585
 
@@ -77,6 +77,7 @@ const headerClass = computed(() => {
77
77
  'border-t',
78
78
  'border-border-neutral-subtle',
79
79
  'text-sm',
80
+ 'text-left',
80
81
  props.fitToContent ? 'w-[1%]' : 'w-auto',
81
82
  props.to ? 'hover:cursor-pointer' : undefined
82
83
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imaginario27/air-ui-ds",
3
- "version": "1.17.0",
3
+ "version": "1.17.2",
4
4
  "author": "imaginario27",
5
5
  "type": "module",
6
6
  "homepage": "https://air-ui.netlify.app/",