@1001-digital/components 1.5.0 → 2.0.1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@1001-digital/components",
3
- "version": "1.5.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "sideEffects": [
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "peerDependencies": {
17
17
  "vue": "^3.5.0",
18
- "@1001-digital/styles": "^1.3.0"
18
+ "@1001-digital/styles": "^2.0.0"
19
19
  },
20
20
  "dependencies": {
21
21
  "@iconify/vue": "^5.0.0",
@@ -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);
@@ -39,23 +39,22 @@ const sidebarOpen = defineModel<boolean>('sidebarOpen', { default: false })
39
39
 
40
40
  <style>
41
41
  @layer components {
42
- html:has(.app-shell) {
43
- scrollbar-gutter: auto;
44
- overflow: hidden;
45
- height: 100dvh;
46
- }
47
-
48
42
  .app-shell {
49
43
  display: flex;
50
- block-size: 100dvh;
51
- overflow: hidden;
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
+ }
52
53
  }
53
54
 
54
55
  .app-shell-main {
55
56
  flex: 1;
56
57
  min-inline-size: 0;
57
- overflow-y: auto;
58
- overscroll-behavior-y: contain;
59
58
  padding-block-start: env(safe-area-inset-top);
60
59
 
61
60
  &:has(+ nav.bottom-nav) {
@@ -6,7 +6,7 @@
6
6
  </nav>
7
7
  </template>
8
8
 
9
- <style>
9
+ <style scoped>
10
10
  @layer components {
11
11
  .bottom-nav {
12
12
  position: fixed;
@@ -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>
@@ -104,7 +104,7 @@ const resolveDisplayValue = (val: any) => {
104
104
  }
105
105
  </script>
106
106
 
107
- <style>
107
+ <style scoped>
108
108
  @layer components {
109
109
  .combobox-root {
110
110
  inline-size: 100%;
@@ -25,7 +25,7 @@
25
25
  @pointerdown="open = false"
26
26
  @click="open = false"
27
27
  >
28
- <Icon type="close" />
28
+ <Icon name="close" />
29
29
  </button>
30
30
 
31
31
  <section>
@@ -233,7 +233,7 @@ onBeforeUnmount(() => {
233
233
  }
234
234
 
235
235
  &::backdrop {
236
- background-color: var(--backdrop-background-color);
236
+ background-color: var(--backdrop-background);
237
237
  backdrop-filter: var(--blur);
238
238
  transition:
239
239
  background-color var(--speed) ease,
@@ -257,7 +257,7 @@ onBeforeUnmount(() => {
257
257
  position: fixed;
258
258
  inset: 0;
259
259
  z-index: var(--z-index-overlay);
260
- background-color: var(--backdrop-background-color);
260
+ background-color: var(--backdrop-background);
261
261
  backdrop-filter: var(--blur);
262
262
  transition:
263
263
  background-color var(--speed) ease,
@@ -71,7 +71,7 @@ const props = withDefaults(
71
71
  const open = defineModel<boolean>('open', { required: true })
72
72
  </script>
73
73
 
74
- <style>
74
+ <style scoped>
75
75
  @layer components {
76
76
  .dropdown {
77
77
  background: var(--dropdown-background);
@@ -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
 
@@ -187,7 +187,7 @@ const open = defineModel<boolean>('open')
187
187
  const placeholderValue = ref(props.placeholder) as ReturnType<typeof ref<DateValue | undefined>>
188
188
  </script>
189
189
 
190
- <style>
190
+ <style scoped>
191
191
  @layer components {
192
192
  .form-date-picker-anchor {
193
193
  display: inline-flex;
@@ -20,7 +20,6 @@
20
20
  @layer components {
21
21
  .form-item {
22
22
  border-radius: var(--border-radius);
23
- overflow: hidden;
24
23
  display: flex;
25
24
  align-items: center;
26
25
  background: var(--background);
@@ -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>
@@ -25,7 +25,15 @@
25
25
  </template>
26
26
 
27
27
  <script setup lang="ts">
28
- import { ref, reactive, computed, watch, watchEffect, onMounted, onBeforeUnmount } from 'vue'
28
+ import {
29
+ ref,
30
+ reactive,
31
+ computed,
32
+ watch,
33
+ watchEffect,
34
+ onMounted,
35
+ onBeforeUnmount,
36
+ } from 'vue'
29
37
  import { useMediaQuery, useScrollLock, useElementSize } from '@vueuse/core'
30
38
 
31
39
  const open = defineModel<boolean>('open', { default: false })
@@ -206,7 +214,7 @@ defineExpose({
206
214
  })
207
215
  </script>
208
216
 
209
- <style>
217
+ <style scoped>
210
218
  @layer components {
211
219
  .sidebar {
212
220
  position: fixed;
@@ -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">
@@ -64,7 +64,7 @@ const props = withDefaults(
64
64
  )
65
65
  </script>
66
66
 
67
- <style>
67
+ <style scoped>
68
68
  @layer components {
69
69
  .tooltip {
70
70
  background: var(--tooltip-background);
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
  }
@@ -7,4 +7,5 @@ export const clientOnlyComponents = [
7
7
  'Popover',
8
8
  'Dropdown',
9
9
  'FormDatePicker',
10
+ 'ColorPicker',
10
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,10 +31,13 @@ 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'
39
43
  export { default as Prose } from './base/components/Prose.vue'