@1001-digital/components 1.4.0 → 2.0.0

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/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@1001-digital/components",
3
- "version": "1.4.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
+ "main": "./src/index.ts",
5
6
  "sideEffects": [
6
7
  "*.css"
7
8
  ],
@@ -14,18 +15,18 @@
14
15
  ],
15
16
  "peerDependencies": {
16
17
  "vue": "^3.5.0",
17
- "@1001-digital/styles": "^1.2.0"
18
+ "@1001-digital/styles": "^2.0.0"
18
19
  },
19
20
  "dependencies": {
20
21
  "@iconify/vue": "^5.0.0",
21
- "@internationalized/date": "^3.8.0",
22
- "@types/luxon": "^3.7.0",
22
+ "@internationalized/date": "^3.12.0",
23
23
  "@visualizevalue/opepicons": "^0.1.0",
24
- "@vueuse/core": "^14.2.0",
24
+ "@vueuse/core": "^14.2.1",
25
25
  "luxon": "^3.7.0",
26
- "reka-ui": "^2.8.0"
26
+ "reka-ui": "^2.9.0"
27
27
  },
28
28
  "devDependencies": {
29
- "vue": "^3.5.0"
29
+ "@types/luxon": "^3.7.0",
30
+ "vue": "^3.5.30"
30
31
  }
31
32
  }
@@ -14,10 +14,14 @@
14
14
  flex-wrap: wrap;
15
15
  gap: var(--spacer-sm);
16
16
 
17
- &:not(.left) {
17
+ &:not(.left):not(.center) {
18
18
  justify-content: flex-end;
19
19
  }
20
20
 
21
+ &.center {
22
+ justify-content: center;
23
+ }
24
+
21
25
  &:empty {
22
26
  display: none !important;
23
27
  }
@@ -10,7 +10,7 @@
10
10
  @click="dismiss"
11
11
  class="close"
12
12
  >
13
- <Icon type="close" />
13
+ <Icon name="close" />
14
14
  </button>
15
15
  <slot />
16
16
  </aside>
@@ -46,7 +46,7 @@ const dismiss = () => {
46
46
  gap: var(--spacer-sm);
47
47
  border: var(--border);
48
48
  border-color: var(--alert-border-color);
49
- background-color: var(--alert-background-color);
49
+ background-color: var(--alert-background);
50
50
  color: var(--alert-color);
51
51
  font-family: var(--font-family);
52
52
  font-size: var(--ui-font-size);
@@ -41,19 +41,24 @@ const sidebarOpen = defineModel<boolean>('sidebarOpen', { default: false })
41
41
  @layer components {
42
42
  .app-shell {
43
43
  display: flex;
44
- min-block-size: var(--100vh);
44
+ min-block-size: 100dvh;
45
+ }
46
+
47
+ html:has(.app-shell nav.bottom-nav) > body {
48
+ border-inline-end: var(--border);
49
+
50
+ .app-shell nav.bottom-nav {
51
+ border-inline-end: var(--border);
52
+ }
45
53
  }
46
54
 
47
55
  .app-shell-main {
48
56
  flex: 1;
49
57
  min-inline-size: 0;
50
- }
51
-
52
- .app-shell:has(.bottom-nav) .app-shell-main {
53
- padding-block-end: var(--bottom-nav-height);
58
+ padding-block-start: env(safe-area-inset-top);
54
59
 
55
- @media (min-width: 1024px) {
56
- padding-block-end: 0;
60
+ &:has(+ nav.bottom-nav) {
61
+ padding-block-end: var(--bottom-nav-height);
57
62
  }
58
63
  }
59
64
  }
@@ -1,6 +1,8 @@
1
1
  <template>
2
2
  <nav class="bottom-nav">
3
- <slot />
3
+ <div class="bottom-nav-items">
4
+ <slot />
5
+ </div>
4
6
  </nav>
5
7
  </template>
6
8
 
@@ -17,12 +19,16 @@
17
19
  border-block-start: var(--border);
18
20
  display: flex;
19
21
  align-items: center;
20
- justify-content: space-evenly;
22
+ justify-content: center;
21
23
  padding-block-end: env(safe-area-inset-bottom);
24
+ }
22
25
 
23
- @media (min-width: 1024px) {
24
- display: none;
25
- }
26
+ .bottom-nav-items {
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: space-evenly;
30
+ inline-size: 100%;
31
+ max-inline-size: var(--bottom-nav-max-inline-size);
26
32
 
27
33
  > a,
28
34
  > button {
@@ -18,11 +18,11 @@
18
18
  >
19
19
  <CalendarHeader class="calendar-header">
20
20
  <CalendarPrev class="calendar-nav">
21
- <Icon type="chevron-left" />
21
+ <Icon name="chevron-left" />
22
22
  </CalendarPrev>
23
23
  <CalendarHeading class="calendar-heading" />
24
24
  <CalendarNext class="calendar-nav">
25
- <Icon type="chevron-right" />
25
+ <Icon name="chevron-right" />
26
26
  </CalendarNext>
27
27
  </CalendarHeader>
28
28
 
@@ -0,0 +1,318 @@
1
+ <template>
2
+ <Popover
3
+ v-model:open="open"
4
+ :side="side"
5
+ :align="align"
6
+ :side-offset="sideOffset"
7
+ class="color-picker-popover"
8
+ >
9
+ <template #trigger>
10
+ <button
11
+ class="color-picker-trigger"
12
+ type="button"
13
+ >
14
+ <ColorSwatch
15
+ :color="hexColor"
16
+ class="color-picker-swatch"
17
+ />
18
+ <span class="color-picker-value">{{ hexColor }}</span>
19
+ </button>
20
+ </template>
21
+
22
+ <div class="color-picker">
23
+ <!-- 2D Color Area (Saturation/Lightness) -->
24
+ <ColorAreaRoot
25
+ v-slot="{ style }"
26
+ :model-value="colorObj"
27
+ color-space="hsl"
28
+ x-channel="saturation"
29
+ y-channel="lightness"
30
+ class="color-picker-area"
31
+ @update:color="handleColorUpdate"
32
+ >
33
+ <ColorAreaArea
34
+ class="color-picker-area-surface"
35
+ :style="style"
36
+ >
37
+ <ColorAreaThumb class="color-picker-thumb" />
38
+ </ColorAreaArea>
39
+ </ColorAreaRoot>
40
+
41
+ <!-- Hue Slider -->
42
+ <ColorSliderRoot
43
+ :model-value="colorObj"
44
+ channel="hue"
45
+ color-space="hsl"
46
+ class="color-picker-slider"
47
+ @update:color="handleColorUpdate"
48
+ >
49
+ <ColorSliderTrack class="color-picker-slider-track">
50
+ <div class="color-picker-slider-track-fill" />
51
+ </ColorSliderTrack>
52
+ <ColorSliderThumb class="color-picker-thumb" />
53
+ </ColorSliderRoot>
54
+
55
+ <!-- Alpha Slider -->
56
+ <ColorSliderRoot
57
+ v-if="alpha"
58
+ :model-value="colorObj"
59
+ channel="alpha"
60
+ color-space="hsl"
61
+ class="color-picker-slider"
62
+ @update:color="handleColorUpdate"
63
+ >
64
+ <ColorSliderTrack
65
+ class="color-picker-slider-track color-picker-alpha-track"
66
+ >
67
+ <div class="color-picker-slider-track-fill" />
68
+ </ColorSliderTrack>
69
+ <ColorSliderThumb class="color-picker-thumb" />
70
+ </ColorSliderRoot>
71
+
72
+ <!-- Color Fields -->
73
+ <FormInputGroup>
74
+ <ColorFieldRoot
75
+ :model-value="hexColor"
76
+ as-child
77
+ @update:model-value="handleHexUpdate"
78
+ >
79
+ <ColorFieldInput
80
+ class="color-picker-input-hex"
81
+ placeholder="#000000"
82
+ />
83
+ </ColorFieldRoot>
84
+ <ColorFieldRoot
85
+ :model-value="colorObj"
86
+ channel="hue"
87
+ color-space="hsl"
88
+ as-child
89
+ @update:color="handleColorUpdate"
90
+ >
91
+ <ColorFieldInput placeholder="H" />
92
+ </ColorFieldRoot>
93
+ <ColorFieldRoot
94
+ :model-value="colorObj"
95
+ channel="saturation"
96
+ color-space="hsl"
97
+ as-child
98
+ @update:color="handleColorUpdate"
99
+ >
100
+ <ColorFieldInput placeholder="S" />
101
+ </ColorFieldRoot>
102
+ <ColorFieldRoot
103
+ :model-value="colorObj"
104
+ channel="lightness"
105
+ color-space="hsl"
106
+ as-child
107
+ @update:color="handleColorUpdate"
108
+ >
109
+ <ColorFieldInput placeholder="L" />
110
+ </ColorFieldRoot>
111
+ </FormInputGroup>
112
+ </div>
113
+ </Popover>
114
+ </template>
115
+
116
+ <script setup lang="ts">
117
+ import { computed, ref, watch } from 'vue'
118
+ import type { Color } from 'reka-ui'
119
+ import {
120
+ ColorAreaArea,
121
+ ColorAreaRoot,
122
+ ColorAreaThumb,
123
+ ColorFieldInput,
124
+ ColorFieldRoot,
125
+ ColorSliderRoot,
126
+ ColorSliderThumb,
127
+ ColorSliderTrack,
128
+ ColorSwatch,
129
+ colorToString,
130
+ normalizeColor,
131
+ } from 'reka-ui'
132
+ import FormInputGroup from './FormInputGroup.vue'
133
+ import Popover from './Popover.vue'
134
+
135
+ const props = withDefaults(
136
+ defineProps<{
137
+ side?: 'top' | 'right' | 'bottom' | 'left'
138
+ align?: 'start' | 'center' | 'end'
139
+ sideOffset?: number
140
+ alpha?: boolean
141
+ }>(),
142
+ {
143
+ side: 'bottom',
144
+ align: 'start',
145
+ sideOffset: 4,
146
+ },
147
+ )
148
+
149
+ const model = defineModel<string>({ default: '#56d799' })
150
+
151
+ const open = ref(false)
152
+ const colorObj = ref<Color>(normalizeColor(model.value))
153
+ const hexColor = computed(() => colorToString(colorObj.value, 'hex'))
154
+
155
+ watch(hexColor, (val) => {
156
+ model.value = val
157
+ })
158
+
159
+ watch(
160
+ () => model.value,
161
+ (val) => {
162
+ const normalized = normalizeColor(val)
163
+ if (colorToString(normalized, 'hex') !== hexColor.value) {
164
+ colorObj.value = normalized
165
+ }
166
+ },
167
+ )
168
+
169
+ function handleColorUpdate(newColor: Color) {
170
+ colorObj.value = newColor
171
+ }
172
+
173
+ function handleHexUpdate(hex: string) {
174
+ colorObj.value = normalizeColor(hex)
175
+ }
176
+ </script>
177
+
178
+ <style scoped>
179
+ @layer components {
180
+ .color-picker-trigger {
181
+ all: unset;
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: var(--size-2);
185
+ padding: var(--ui-padding-block) var(--ui-padding-inline);
186
+ background: var(--button-background);
187
+ border-radius: var(--button-border-radius);
188
+ box-shadow: var(--border-shadow);
189
+ font-family: var(--font-family);
190
+ font-size: var(--ui-font-size);
191
+ cursor: pointer;
192
+ transition:
193
+ box-shadow var(--speed),
194
+ background var(--speed);
195
+ max-width: var(--color-picker-trigger-max-width);
196
+
197
+ &:is(:hover, :focus) {
198
+ box-shadow: var(--border-shadow-highlight);
199
+ }
200
+
201
+ &:focus-visible {
202
+ outline: 2px solid var(--primary);
203
+ outline-offset: 2px;
204
+ }
205
+ }
206
+
207
+ .color-picker-swatch {
208
+ inline-size: var(--size-4);
209
+ block-size: var(--size-4);
210
+ border-radius: var(--border-radius);
211
+ background-color: var(--reka-color-swatch-color);
212
+ box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15);
213
+ flex-shrink: 0;
214
+ }
215
+
216
+ .color-picker {
217
+ display: grid;
218
+ gap: var(--spacer);
219
+ }
220
+
221
+ .color-picker-area {
222
+ position: relative;
223
+ }
224
+
225
+ .color-picker-area-surface {
226
+ position: relative;
227
+ inline-size: 100%;
228
+ block-size: var(--color-picker-area-height);
229
+ border-radius: var(--border-radius);
230
+ overflow: hidden;
231
+
232
+ &:focus-visible {
233
+ outline: 2px solid var(--primary);
234
+ outline-offset: 2px;
235
+ }
236
+ }
237
+
238
+ .color-picker-thumb {
239
+ all: unset;
240
+ display: block;
241
+ inline-size: var(--color-picker-thumb-size);
242
+ block-size: var(--color-picker-thumb-size);
243
+ border-radius: 50%;
244
+ background: var(--color-picker-thumb-background);
245
+ box-shadow:
246
+ 0 0 0 2px var(--color-picker-thumb-background),
247
+ 0 1px 4px rgb(0 0 0 / 0.3);
248
+ cursor: pointer;
249
+ transition: transform var(--speed);
250
+
251
+ &:is(:hover, :focus) {
252
+ transform: scale(1.1);
253
+ }
254
+
255
+ &:focus-visible {
256
+ outline: 2px solid var(--primary);
257
+ outline-offset: 2px;
258
+ }
259
+ }
260
+
261
+ .color-picker-slider {
262
+ position: relative;
263
+ display: flex;
264
+ align-items: center;
265
+ inline-size: 100%;
266
+ block-size: var(--color-picker-thumb-size);
267
+ }
268
+
269
+ .color-picker-slider-track {
270
+ position: relative;
271
+ flex-grow: 1;
272
+ block-size: var(--color-picker-track-size);
273
+ border-radius: var(--color-picker-track-radius);
274
+ overflow: hidden;
275
+ }
276
+
277
+ .color-picker-slider-track-fill {
278
+ position: absolute;
279
+ inset: 0;
280
+ border-radius: var(--color-picker-track-radius);
281
+ }
282
+
283
+ .color-picker-alpha-track {
284
+ background-image:
285
+ linear-gradient(
286
+ 45deg,
287
+ var(--color-picker-checkerboard) 25%,
288
+ transparent 25%
289
+ ),
290
+ linear-gradient(
291
+ -45deg,
292
+ var(--color-picker-checkerboard) 25%,
293
+ transparent 25%
294
+ ),
295
+ linear-gradient(
296
+ 45deg,
297
+ transparent 75%,
298
+ var(--color-picker-checkerboard) 75%
299
+ ),
300
+ linear-gradient(
301
+ -45deg,
302
+ transparent 75%,
303
+ var(--color-picker-checkerboard) 75%
304
+ );
305
+ background-size: 8px 8px;
306
+ background-position:
307
+ 0 0,
308
+ 0 4px,
309
+ 4px -4px,
310
+ -4px 0;
311
+ }
312
+
313
+ .color-picker :deep(input) {
314
+ text-align: center;
315
+ font-size: var(--font-xs);
316
+ }
317
+ }
318
+ </style>
@@ -17,7 +17,7 @@
17
17
  :disabled="disabled"
18
18
  />
19
19
  <ComboboxTrigger class="combobox-trigger">
20
- <Icon type="chevron-down" />
20
+ <Icon name="chevron-down" />
21
21
  </ComboboxTrigger>
22
22
  </ComboboxAnchor>
23
23
 
@@ -39,7 +39,7 @@
39
39
  >
40
40
  {{ option[labelKey] }}
41
41
  <ComboboxItemIndicator class="combobox-indicator">
42
- <Icon type="check" />
42
+ <Icon name="check" />
43
43
  </ComboboxItemIndicator>
44
44
  </ComboboxItem>
45
45
  </ComboboxViewport>
@@ -2,6 +2,7 @@
2
2
  <Teleport :to="teleportTarget || 'body'">
3
3
  <Transition
4
4
  :css="false"
5
+ appear
5
6
  @enter="onEnter"
6
7
  @leave="onLeave"
7
8
  @after-leave="() => emit('closed')"
@@ -15,24 +16,26 @@
15
16
  @cancel.stop.prevent="closable && (open = false)"
16
17
  @click="onDialogClick"
17
18
  >
18
- <h1 v-if="title">{{ title }}</h1>
19
- <button
20
- v-if="closable"
21
- class="close"
22
- :title="`Close ${title || 'Dialog'}`"
23
- @pointerdown="open = false"
24
- @click="open = false"
25
- >
26
- <Icon type="close" />
27
- </button>
28
-
29
- <section>
30
- <slot />
31
- </section>
32
-
33
- <footer v-if="$slots.footer">
34
- <slot name="footer" />
35
- </footer>
19
+ <div class="dialog-content">
20
+ <h1 v-if="title">{{ title }}</h1>
21
+ <button
22
+ v-if="closable"
23
+ class="close"
24
+ :title="`Close ${title || 'Dialog'}`"
25
+ @pointerdown="open = false"
26
+ @click="open = false"
27
+ >
28
+ <Icon name="close" />
29
+ </button>
30
+
31
+ <section>
32
+ <slot />
33
+ </section>
34
+
35
+ <footer v-if="$slots.footer">
36
+ <slot name="footer" />
37
+ </footer>
38
+ </div>
36
39
  </component>
37
40
  </Transition>
38
41
 
@@ -144,14 +147,71 @@ onBeforeUnmount(() => {
144
147
  background: var(--background);
145
148
  color: var(--color);
146
149
  border: var(--border);
147
- border-radius: var(--border-radius);
150
+ border-radius: var(--dialog-border-radius);
148
151
  padding: 0;
149
- max-block-size: 80dvh;
150
- container-type: inline-size;
151
- display: grid;
152
- grid-template-rows: auto 1fr auto;
153
152
  overflow: hidden;
154
153
 
154
+ > .dialog-content {
155
+ display: grid;
156
+ grid-template-rows: auto 1fr auto;
157
+ max-block-size: 80dvh;
158
+
159
+ > h1:first-child,
160
+ > .close {
161
+ display: flex;
162
+ align-items: center;
163
+ block-size: calc(var(--spacer) * 2);
164
+ box-shadow: var(--border-shadow);
165
+ padding-inline-start: var(--spacer);
166
+ font-family: var(--font-family);
167
+ font-size: var(--ui-font-size);
168
+ text-transform: var(--ui-text-transform);
169
+ margin: 0;
170
+ }
171
+
172
+ > h1:first-child {
173
+ padding-right: calc(var(--spacer) * 3);
174
+ }
175
+
176
+ > .close {
177
+ position: absolute;
178
+ top: 0;
179
+ right: 0;
180
+ inline-size: calc(var(--spacer) * 2);
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ padding: 0;
185
+ border-radius: 0;
186
+ border-start-end-radius: var(--dialog-border-radius);
187
+
188
+ &:is(:hover, :active, :focus, .active) {
189
+ outline: none;
190
+ }
191
+ }
192
+
193
+ > section {
194
+ overflow-y: auto;
195
+ overscroll-behavior: contain;
196
+ padding: var(--spacer);
197
+ display: grid;
198
+ gap: var(--spacer);
199
+ }
200
+
201
+ > footer {
202
+ display: flex;
203
+ gap: var(--spacer);
204
+ justify-content: safe flex-end;
205
+ padding: var(--spacer);
206
+ border-block-start: var(--border);
207
+ overflow-x: auto;
208
+
209
+ &:empty {
210
+ display: none;
211
+ }
212
+ }
213
+ }
214
+
155
215
  /* Entry/exit animations */
156
216
  opacity: 1;
157
217
  scale: 1;
@@ -173,7 +233,7 @@ onBeforeUnmount(() => {
173
233
  }
174
234
 
175
235
  &::backdrop {
176
- background-color: var(--backdrop-background-color);
236
+ background-color: var(--backdrop-background);
177
237
  backdrop-filter: var(--blur);
178
238
  transition:
179
239
  background-color var(--speed) ease,
@@ -197,7 +257,7 @@ onBeforeUnmount(() => {
197
257
  position: fixed;
198
258
  inset: 0;
199
259
  z-index: var(--z-index-overlay);
200
- background-color: var(--backdrop-background-color);
260
+ background-color: var(--backdrop-background);
201
261
  backdrop-filter: var(--blur);
202
262
  transition:
203
263
  background-color var(--speed) ease,
@@ -213,61 +273,6 @@ onBeforeUnmount(() => {
213
273
  outline: none;
214
274
  }
215
275
 
216
- > h1:first-child,
217
- > .close {
218
- display: flex;
219
- align-items: center;
220
- block-size: calc(var(--spacer) * 2);
221
- box-shadow: var(--border-shadow);
222
- padding-inline-start: var(--spacer);
223
- font-family: var(--font-family);
224
- font-size: var(--ui-font-size);
225
- text-transform: var(--ui-text-transform);
226
- margin: 0;
227
- }
228
-
229
- > h1:first-child {
230
- padding-right: calc(var(--spacer) * 3);
231
- }
232
-
233
- > .close {
234
- position: absolute;
235
- top: 0;
236
- right: 0;
237
- inline-size: calc(var(--spacer) * 2);
238
- display: flex;
239
- align-items: center;
240
- justify-content: center;
241
- padding: 0;
242
- border-radius: 0;
243
- border-start-end-radius: var(--border-radius);
244
-
245
- &:is(:hover, :active, :focus, .active) {
246
- outline: none;
247
- }
248
- }
249
-
250
- > section {
251
- overflow-y: auto;
252
- overscroll-behavior: contain;
253
- padding: var(--spacer);
254
- display: grid;
255
- gap: var(--spacer);
256
- }
257
-
258
- > footer {
259
- display: flex;
260
- gap: var(--spacer);
261
- justify-content: safe flex-end;
262
- padding: var(--spacer);
263
- border-block-start: var(--border);
264
- overflow-x: auto;
265
-
266
- &:empty {
267
- display: none;
268
- }
269
- }
270
-
271
276
  &.large {
272
277
  --dialog-width: min(90vw, 64rem);
273
278
  }
@@ -7,7 +7,7 @@
7
7
  @select="(e: Event) => emit('select', e)"
8
8
  >
9
9
  <DropdownMenuItemIndicator class="dropdown-item-indicator">
10
- <Icon type="check" />
10
+ <Icon name="check" />
11
11
  </DropdownMenuItemIndicator>
12
12
  <slot />
13
13
  </DropdownMenuCheckboxItem>
@@ -7,7 +7,7 @@
7
7
  @select="(e: Event) => emit('select', e)"
8
8
  >
9
9
  <DropdownMenuItemIndicator class="dropdown-item-indicator">
10
- <Icon type="check" />
10
+ <Icon name="check" />
11
11
  </DropdownMenuItemIndicator>
12
12
  <slot />
13
13
  </DropdownMenuRadioItem>
@@ -8,7 +8,7 @@
8
8
  class="form-checkbox-button"
9
9
  >
10
10
  <CheckboxIndicator class="form-checkbox-indicator">
11
- <Icon type="check" />
11
+ <Icon name="check" />
12
12
  </CheckboxIndicator>
13
13
  </CheckboxRoot>
14
14
  <span v-if="$slots.default"><slot /></span>
@@ -46,7 +46,7 @@
46
46
  </DatePickerField>
47
47
 
48
48
  <DatePickerTrigger class="form-date-picker-trigger">
49
- <Icon type="calendar" />
49
+ <Icon name="calendar" />
50
50
  </DatePickerTrigger>
51
51
  </DatePickerAnchor>
52
52
 
@@ -65,11 +65,11 @@
65
65
  >
66
66
  <DatePickerHeader class="form-date-picker-header">
67
67
  <DatePickerPrev class="form-date-picker-nav">
68
- <Icon type="chevron-left" />
68
+ <Icon name="chevron-left" />
69
69
  </DatePickerPrev>
70
70
  <DatePickerHeading class="form-date-picker-heading" />
71
71
  <DatePickerNext class="form-date-picker-nav">
72
- <Icon type="chevron-right" />
72
+ <Icon name="chevron-right" />
73
73
  </DatePickerNext>
74
74
  </DatePickerHeader>
75
75
 
@@ -65,24 +65,14 @@
65
65
  border-end-end-radius: var(--border-radius);
66
66
  }
67
67
 
68
- &:has(> .prefix) {
68
+ &:has(> .prefix) :deep(> :last-child) {
69
69
  border-start-start-radius: 0;
70
70
  border-end-start-radius: 0;
71
-
72
- & :deep(> :last-child) {
73
- border-start-start-radius: 0;
74
- border-end-start-radius: 0;
75
- }
76
71
  }
77
72
 
78
- &:has(> .suffix) {
73
+ &:has(> .suffix) :deep(> :first-child) {
79
74
  border-start-end-radius: 0;
80
75
  border-end-end-radius: 0;
81
-
82
- & :deep(> :first-child) {
83
- border-start-end-radius: 0;
84
- border-end-end-radius: 0;
85
- }
86
76
  }
87
77
  }
88
78
  }
@@ -8,7 +8,7 @@
8
8
  <SelectTrigger class="form-select-trigger">
9
9
  <SelectValue :placeholder="placeholder" />
10
10
  <SelectIcon class="form-select-icon">
11
- <Icon type="chevron-down" />
11
+ <Icon name="chevron-down" />
12
12
  </SelectIcon>
13
13
  </SelectTrigger>
14
14
 
@@ -27,7 +27,7 @@
27
27
  >
28
28
  <SelectItemText>{{ option[labelKey] }}</SelectItemText>
29
29
  <SelectItemIndicator class="form-select-indicator">
30
- <Icon type="check" />
30
+ <Icon name="check" />
31
31
  </SelectItemIndicator>
32
32
  </SelectItem>
33
33
  </SelectViewport>
@@ -11,11 +11,11 @@ import { computed, inject } from 'vue'
11
11
  import { Icon as IconifyIcon } from '@iconify/vue'
12
12
  import { IconAliasesKey, defaultIconAliases } from '../icons'
13
13
 
14
- const props = defineProps<{ type: string }>()
14
+ const props = defineProps<{ name: string }>()
15
15
 
16
16
  const aliases = inject(IconAliasesKey, defaultIconAliases)
17
17
 
18
- const resolvedIcon = computed(() => aliases[props.type] || props.type)
18
+ const resolvedIcon = computed(() => aliases[props.name] || props.name)
19
19
  </script>
20
20
 
21
21
  <style scoped>
@@ -29,7 +29,7 @@
29
29
  class="popover-close tertiary"
30
30
  aria-label="Close"
31
31
  >
32
- <Icon type="close" />
32
+ <Icon name="close" />
33
33
  </PopoverClose>
34
34
 
35
35
  <section>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <div
3
+ class="prose"
4
+ :class="{ centered }"
5
+ >
6
+ <slot />
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ defineProps<{
12
+ centered?: boolean
13
+ }>()
14
+ </script>
@@ -82,6 +82,7 @@ onMounted(() => {
82
82
  if (isLargeScreen.value) return
83
83
 
84
84
  const touch = e.touches[0]
85
+ if (!touch) return
85
86
  startX = touch.clientX
86
87
  startY = touch.clientY
87
88
  tracking = false
@@ -103,6 +104,7 @@ onMounted(() => {
103
104
  if (!tracking || isLargeScreen.value) return
104
105
 
105
106
  const touch = e.touches[0]
107
+ if (!touch) return
106
108
  const dx = touch.clientX - startX
107
109
  const dy = touch.clientY - startY
108
110
 
@@ -7,7 +7,7 @@
7
7
  v-if="dismissable"
8
8
  @click="emit('dismiss')"
9
9
  >
10
- <Icon type="close" />
10
+ <Icon name="close" />
11
11
  </Button>
12
12
  </span>
13
13
  </template>
@@ -25,7 +25,7 @@
25
25
  :as="Button"
26
26
  aria-label="Close"
27
27
  >
28
- <Icon type="close" />
28
+ <Icon name="close" />
29
29
  </ToastClose>
30
30
 
31
31
  <section v-if="toast.description || toast.action || toast.progress">
@@ -129,7 +129,7 @@ const onClose = (id: string) => {
129
129
  max-inline-size: calc(100vw - var(--spacer) * 2);
130
130
  padding: 0;
131
131
  border: var(--border);
132
- border-radius: var(--border-radius);
132
+ border-radius: var(--toast-border-radius);
133
133
  overflow: hidden;
134
134
  font-family: var(--font-family);
135
135
  font-size: var(--ui-font-size);
@@ -248,7 +248,7 @@ const onClose = (id: string) => {
248
248
  right: 0;
249
249
  box-shadow: var(--border-shadow) !important;
250
250
  border-radius: 0 !important;
251
- border-start-end-radius: var(--border-radius) !important;
251
+ border-start-end-radius: var(--toast-border-radius) !important;
252
252
  }
253
253
 
254
254
  .actions {
package/src/base/icons.ts CHANGED
@@ -14,9 +14,10 @@ export const defaultIconAliases: IconAliases = {
14
14
  close: 'lucide:x',
15
15
  copy: 'lucide:copy',
16
16
  edit: 'lucide:pencil',
17
- help: 'lucide:circle-question-mark',
17
+ help: 'lucide:circle-help',
18
18
  home: 'lucide:house',
19
19
  link: 'lucide:link',
20
20
  loader: 'lucide:loader-2',
21
+ menu: 'lucide:menu',
21
22
  wallet: 'lucide:wallet',
22
23
  }
@@ -0,0 +1,11 @@
1
+ // Components that require browser APIs and must be rendered client-only
2
+ export const clientOnlyComponents = [
3
+ 'Combobox',
4
+ 'ConfirmDialog',
5
+ 'Dialog',
6
+ 'Toasts',
7
+ 'Popover',
8
+ 'Dropdown',
9
+ 'FormDatePicker',
10
+ 'ColorPicker',
11
+ ]
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export { default as BottomNav } from './base/components/BottomNav.vue'
6
6
  export { default as Button } from './base/components/Button.vue'
7
7
  export { default as Calendar } from './base/components/Calendar.vue'
8
8
  export { default as Card } from './base/components/Card.vue'
9
+ export { default as ColorPicker } from './base/components/ColorPicker.vue'
9
10
  export { default as Combobox } from './base/components/Combobox.vue'
10
11
  export { default as ConfirmDialog } from './base/components/ConfirmDialog.vue'
11
12
  export { default as CardLink } from './base/components/CardLink.vue'
@@ -30,12 +31,16 @@ export { default as FormItem } from './base/components/FormItem.vue'
30
31
  export { default as FormLabel } from './base/components/FormLabel.vue'
31
32
  export { default as FormRadioGroup } from './base/components/FormRadioGroup.vue'
32
33
  export { default as FormSelect } from './base/components/FormSelect.vue'
34
+ export { default as FormSlider } from './base/components/FormSlider.vue'
35
+ export { default as FormSwitch } from './base/components/FormSwitch.vue'
33
36
  export { default as FormTextarea } from './base/components/FormTextarea.vue'
34
37
  export { default as Icon } from './base/components/Icon.vue'
35
38
  export { default as Loading } from './base/components/Loading.vue'
36
39
  export { default as Opepicon } from './base/components/Opepicon.vue'
40
+ export { default as PinInput } from './base/components/PinInput.vue'
37
41
  export { default as Popover } from './base/components/Popover.vue'
38
42
  export { default as Progress } from './base/components/Progress.vue'
43
+ export { default as Prose } from './base/components/Prose.vue'
39
44
  export { default as Sidebar } from './base/components/Sidebar.vue'
40
45
  export { default as Tag } from './base/components/Tag.vue'
41
46
  export { default as Tags } from './base/components/Tags.vue'
@@ -84,3 +89,5 @@ export type { DateValue } from '@internationalized/date'
84
89
  export { IconAliasesKey, defaultIconAliases } from './base/icons'
85
90
  export type { IconAliases } from './base/icons'
86
91
  export { LinkComponentKey } from './base/link'
92
+
93
+ export { clientOnlyComponents } from './client-only'