@1001-digital/components 0.0.4 → 1.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.
Files changed (32) hide show
  1. package/package.json +11 -2
  2. package/src/base/components/Button.vue +2 -2
  3. package/src/base/components/Calendar.vue +227 -0
  4. package/src/base/components/Combobox.vue +241 -0
  5. package/src/base/components/ConfirmDialog.vue +33 -0
  6. package/src/base/components/Dialog.vue +7 -1
  7. package/src/base/components/FormDateField.vue +111 -0
  8. package/src/base/components/FormDatePicker.vue +382 -0
  9. package/src/base/components/FormSlider.vue +142 -0
  10. package/src/base/components/FormSwitch.vue +103 -0
  11. package/src/base/components/Globals.vue +9 -0
  12. package/src/base/components/Opepicon.vue +45 -0
  13. package/src/base/components/PinInput.vue +105 -0
  14. package/src/base/components/Progress.vue +66 -0
  15. package/src/base/components/Toasts.vue +6 -1
  16. package/src/base/composables/confirm.ts +29 -0
  17. package/src/base/composables/toast.ts +1 -0
  18. package/src/base/icons.ts +3 -1
  19. package/src/evm/components/EvmAvatar.vue +62 -0
  20. package/src/evm/components/EvmConnect.vue +83 -32
  21. package/src/evm/components/EvmConnectorQR.vue +12 -42
  22. package/src/evm/components/EvmProfile.vue +183 -0
  23. package/src/evm/components/EvmSwitchNetwork.vue +130 -0
  24. package/src/evm/components/EvmTransactionFlow.vue +41 -11
  25. package/src/evm/components/EvmWalletConnectWallets.vue +199 -0
  26. package/src/evm/composables/chainId.ts +2 -2
  27. package/src/evm/composables/uri.ts +11 -0
  28. package/src/evm/composables/walletExplorer.ts +130 -0
  29. package/src/evm/config.ts +1 -0
  30. package/src/evm/index.ts +9 -0
  31. package/src/evm/utils/uri.ts +24 -0
  32. package/src/index.ts +18 -0
@@ -0,0 +1,382 @@
1
+ <template>
2
+ <DatePickerRoot
3
+ v-model="model"
4
+ v-model:open="open"
5
+ v-model:placeholder="placeholderValue"
6
+ :disabled="disabled"
7
+ :readonly="readonly"
8
+ :granularity="granularity"
9
+ :locale="locale"
10
+ :min-value="minValue"
11
+ :max-value="maxValue"
12
+ :is-date-disabled="isDateDisabled"
13
+ :is-date-unavailable="isDateUnavailable"
14
+ :number-of-months="numberOfMonths"
15
+ :fixed-weeks="fixedWeeks"
16
+ :week-starts-on="weekStartsOn"
17
+ :hour-cycle="hourCycle"
18
+ :name="name"
19
+ :required="required"
20
+ :close-on-date-select="closeOnSelect"
21
+ >
22
+ <DatePickerAnchor class="form-date-picker-anchor">
23
+ <DatePickerField
24
+ v-slot="{ segments }"
25
+ class="form-date-picker-field"
26
+ >
27
+ <template
28
+ v-for="segment in segments"
29
+ :key="segment.part"
30
+ >
31
+ <DatePickerInput
32
+ v-if="segment.part === 'literal'"
33
+ :part="segment.part"
34
+ class="form-date-picker-literal"
35
+ >
36
+ {{ segment.value }}
37
+ </DatePickerInput>
38
+ <DatePickerInput
39
+ v-else
40
+ :part="segment.part"
41
+ class="form-date-picker-segment"
42
+ >
43
+ {{ segment.value }}
44
+ </DatePickerInput>
45
+ </template>
46
+ </DatePickerField>
47
+
48
+ <DatePickerTrigger class="form-date-picker-trigger">
49
+ <Icon type="calendar" />
50
+ </DatePickerTrigger>
51
+ </DatePickerAnchor>
52
+
53
+ <DatePickerContent
54
+ class="form-date-picker-content"
55
+ :side="side"
56
+ :align="align"
57
+ :side-offset="sideOffset"
58
+ :align-offset="alignOffset"
59
+ :avoid-collisions="avoidCollisions"
60
+ :collision-padding="collisionPadding"
61
+ >
62
+ <DatePickerCalendar
63
+ v-slot="{ grid, weekDays }"
64
+ class="form-date-picker-calendar"
65
+ >
66
+ <DatePickerHeader class="form-date-picker-header">
67
+ <DatePickerPrev class="form-date-picker-nav">
68
+ <Icon type="chevron-left" />
69
+ </DatePickerPrev>
70
+ <DatePickerHeading class="form-date-picker-heading" />
71
+ <DatePickerNext class="form-date-picker-nav">
72
+ <Icon type="chevron-right" />
73
+ </DatePickerNext>
74
+ </DatePickerHeader>
75
+
76
+ <div class="form-date-picker-grids">
77
+ <DatePickerGrid
78
+ v-for="month in grid"
79
+ :key="month.value.toString()"
80
+ :value="month"
81
+ class="form-date-picker-grid"
82
+ >
83
+ <DatePickerGridHead>
84
+ <DatePickerGridRow class="form-date-picker-grid-row">
85
+ <DatePickerHeadCell
86
+ v-for="day in weekDays"
87
+ :key="day"
88
+ class="form-date-picker-head-cell"
89
+ >
90
+ {{ day }}
91
+ </DatePickerHeadCell>
92
+ </DatePickerGridRow>
93
+ </DatePickerGridHead>
94
+
95
+ <DatePickerGridBody>
96
+ <DatePickerGridRow
97
+ v-for="(row, i) in month.rows"
98
+ :key="i"
99
+ class="form-date-picker-grid-row"
100
+ >
101
+ <DatePickerCell
102
+ v-for="date in row"
103
+ :key="date.toString()"
104
+ :date="date"
105
+ class="form-date-picker-cell"
106
+ >
107
+ <DatePickerCellTrigger
108
+ :day="date"
109
+ :month="month.value"
110
+ class="form-date-picker-cell-trigger"
111
+ />
112
+ </DatePickerCell>
113
+ </DatePickerGridRow>
114
+ </DatePickerGridBody>
115
+ </DatePickerGrid>
116
+ </div>
117
+ </DatePickerCalendar>
118
+ </DatePickerContent>
119
+ </DatePickerRoot>
120
+ </template>
121
+
122
+ <script setup lang="ts">
123
+ import { ref } from 'vue'
124
+ import type { DateValue } from '@internationalized/date'
125
+ import {
126
+ DatePickerAnchor,
127
+ DatePickerCalendar,
128
+ DatePickerCell,
129
+ DatePickerCellTrigger,
130
+ DatePickerContent,
131
+ DatePickerField,
132
+ DatePickerGrid,
133
+ DatePickerGridBody,
134
+ DatePickerGridHead,
135
+ DatePickerGridRow,
136
+ DatePickerHeadCell,
137
+ DatePickerHeader,
138
+ DatePickerHeading,
139
+ DatePickerInput,
140
+ DatePickerNext,
141
+ DatePickerPrev,
142
+ DatePickerRoot,
143
+ DatePickerTrigger,
144
+ } from 'reka-ui'
145
+ import Icon from './Icon.vue'
146
+
147
+ const props = withDefaults(
148
+ defineProps<{
149
+ disabled?: boolean
150
+ readonly?: boolean
151
+ granularity?: 'day' | 'hour' | 'minute' | 'second'
152
+ locale?: string
153
+ minValue?: DateValue
154
+ maxValue?: DateValue
155
+ isDateDisabled?: (date: DateValue) => boolean
156
+ isDateUnavailable?: (date: DateValue) => boolean
157
+ numberOfMonths?: number
158
+ fixedWeeks?: boolean
159
+ weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6
160
+ hourCycle?: 12 | 24
161
+ name?: string
162
+ required?: boolean
163
+ placeholder?: DateValue
164
+ closeOnSelect?: boolean
165
+ side?: 'top' | 'right' | 'bottom' | 'left'
166
+ align?: 'start' | 'center' | 'end'
167
+ sideOffset?: number
168
+ alignOffset?: number
169
+ avoidCollisions?: boolean
170
+ collisionPadding?: number
171
+ }>(),
172
+ {
173
+ locale: 'en',
174
+ granularity: 'day',
175
+ numberOfMonths: 1,
176
+ closeOnSelect: true,
177
+ side: 'bottom',
178
+ align: 'start',
179
+ sideOffset: 4,
180
+ avoidCollisions: true,
181
+ collisionPadding: 8,
182
+ },
183
+ )
184
+
185
+ const model = defineModel<DateValue | undefined>()
186
+ const open = defineModel<boolean>('open')
187
+ const placeholderValue = ref(props.placeholder) as ReturnType<typeof ref<DateValue | undefined>>
188
+ </script>
189
+
190
+ <style>
191
+ @layer components {
192
+ .form-date-picker-anchor {
193
+ display: inline-flex;
194
+ align-items: center;
195
+ background: var(--date-field-background);
196
+ block-size: var(--form-item-height);
197
+ box-shadow: var(--border-shadow);
198
+ border-radius: var(--border-radius);
199
+
200
+ &[data-disabled] {
201
+ opacity: 0.5;
202
+ cursor: not-allowed;
203
+ }
204
+ }
205
+
206
+ .form-date-picker-field {
207
+ display: inline-flex;
208
+ align-items: center;
209
+ padding-inline-start: var(--ui-padding-inline);
210
+ font-size: var(--font-sm);
211
+ }
212
+
213
+ .form-date-picker-literal {
214
+ color: var(--muted);
215
+ padding: 0 1px;
216
+ }
217
+
218
+ .form-date-picker-segment {
219
+ padding: var(--date-field-segment-padding);
220
+ border-radius: var(--date-field-segment-border-radius);
221
+ outline: none;
222
+ color: var(--color);
223
+
224
+ &[data-placeholder] {
225
+ color: var(--muted);
226
+ }
227
+
228
+ &:focus {
229
+ background: var(--date-field-segment-focus-background);
230
+ color: var(--date-field-segment-focus-color);
231
+ }
232
+ }
233
+
234
+ .form-date-picker-trigger {
235
+ all: unset;
236
+ display: inline-flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ padding-inline: var(--ui-padding-inline);
240
+ block-size: 100%;
241
+ cursor: pointer;
242
+ color: var(--date-picker-trigger-icon-color);
243
+
244
+ &:hover {
245
+ color: var(--color);
246
+ }
247
+ }
248
+
249
+ .form-date-picker-content {
250
+ background: var(--date-picker-content-background);
251
+ border: var(--date-picker-content-border);
252
+ border-radius: var(--date-picker-content-border-radius);
253
+ padding: var(--spacer);
254
+ z-index: var(--z-index-ui);
255
+ transform-origin: var(--reka-popper-transform-origin);
256
+
257
+ opacity: 1;
258
+ scale: 1;
259
+ transition:
260
+ opacity var(--speed) ease,
261
+ scale var(--speed) ease;
262
+
263
+ @starting-style {
264
+ opacity: 0;
265
+ scale: 0.95;
266
+ }
267
+
268
+ &[data-state='closed'] {
269
+ opacity: 0;
270
+ scale: 0.95;
271
+ }
272
+ }
273
+
274
+ .form-date-picker-calendar {
275
+ display: grid;
276
+ gap: var(--spacer-sm);
277
+ }
278
+
279
+ .form-date-picker-header {
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: space-between;
283
+ gap: var(--spacer-sm);
284
+ }
285
+
286
+ .form-date-picker-heading {
287
+ font-family: var(--font-family);
288
+ font-size: var(--ui-font-size);
289
+ text-transform: var(--ui-text-transform);
290
+ font-weight: 500;
291
+ }
292
+
293
+ .form-date-picker-nav {
294
+ all: unset;
295
+ display: inline-flex;
296
+ align-items: center;
297
+ justify-content: center;
298
+ cursor: pointer;
299
+ block-size: var(--calendar-nav-size);
300
+ inline-size: var(--calendar-nav-size);
301
+ border-radius: var(--calendar-cell-border-radius);
302
+
303
+ &:hover {
304
+ background: var(--calendar-hover-background);
305
+ }
306
+
307
+ &:disabled {
308
+ opacity: 0.5;
309
+ cursor: not-allowed;
310
+ }
311
+ }
312
+
313
+ .form-date-picker-grids {
314
+ display: flex;
315
+ gap: var(--spacer);
316
+ }
317
+
318
+ .form-date-picker-grid {
319
+ border-collapse: collapse;
320
+ }
321
+
322
+ .form-date-picker-grid-row {
323
+ display: flex;
324
+ }
325
+
326
+ .form-date-picker-head-cell {
327
+ font-family: var(--font-family);
328
+ font-size: var(--font-xs);
329
+ text-transform: var(--ui-text-transform);
330
+ color: var(--muted);
331
+ inline-size: var(--calendar-cell-size);
332
+ block-size: var(--calendar-cell-size);
333
+ display: flex;
334
+ align-items: center;
335
+ justify-content: center;
336
+ }
337
+
338
+ .form-date-picker-cell {
339
+ padding: 1px;
340
+ }
341
+
342
+ .form-date-picker-cell-trigger {
343
+ all: unset;
344
+ display: flex;
345
+ align-items: center;
346
+ justify-content: center;
347
+ inline-size: var(--calendar-cell-size);
348
+ block-size: var(--calendar-cell-size);
349
+ border-radius: var(--calendar-cell-border-radius);
350
+ font-size: var(--font-sm);
351
+ cursor: pointer;
352
+
353
+ &:hover {
354
+ background: var(--calendar-hover-background);
355
+ }
356
+
357
+ &[data-selected] {
358
+ background: var(--calendar-selected-background);
359
+ color: var(--calendar-selected-color);
360
+ }
361
+
362
+ &[data-today]:not([data-selected]) {
363
+ border: var(--calendar-today-border);
364
+ }
365
+
366
+ &[data-outside-month] {
367
+ opacity: 0.3;
368
+ }
369
+
370
+ &[data-unavailable] {
371
+ opacity: 0.3;
372
+ text-decoration: line-through;
373
+ cursor: not-allowed;
374
+ }
375
+
376
+ &[data-disabled] {
377
+ opacity: 0.3;
378
+ cursor: not-allowed;
379
+ }
380
+ }
381
+ }
382
+ </style>
@@ -0,0 +1,142 @@
1
+ <template>
2
+ <SliderRoot
3
+ v-model="model"
4
+ class="form-slider"
5
+ :disabled="disabled"
6
+ :min="min"
7
+ :max="max"
8
+ :step="step"
9
+ :orientation="orientation"
10
+ :inverted="inverted"
11
+ :min-steps-between-thumbs="minStepsBetweenThumbs"
12
+ :name="name"
13
+ :required="required"
14
+ :dir="dir"
15
+ @value-commit="$emit('valueCommit', $event)"
16
+ >
17
+ <SliderTrack class="form-slider-track">
18
+ <SliderRange class="form-slider-range" />
19
+ </SliderTrack>
20
+ <SliderThumb
21
+ v-for="(_, i) in thumbCount"
22
+ :key="i"
23
+ class="form-slider-thumb"
24
+ />
25
+ </SliderRoot>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { computed } from 'vue'
30
+ import { SliderRange, SliderRoot, SliderThumb, SliderTrack } from 'reka-ui'
31
+
32
+ const model = defineModel<number[]>()
33
+
34
+ const props = withDefaults(
35
+ defineProps<{
36
+ disabled?: boolean
37
+ min?: number
38
+ max?: number
39
+ step?: number
40
+ orientation?: 'horizontal' | 'vertical'
41
+ inverted?: boolean
42
+ minStepsBetweenThumbs?: number
43
+ name?: string
44
+ required?: boolean
45
+ dir?: 'ltr' | 'rtl'
46
+ }>(),
47
+ {
48
+ min: 0,
49
+ max: 100,
50
+ step: 1,
51
+ orientation: 'horizontal',
52
+ minStepsBetweenThumbs: 0,
53
+ },
54
+ )
55
+
56
+ defineEmits<{
57
+ valueCommit: [value: number[]]
58
+ }>()
59
+
60
+ const thumbCount = computed(() => model.value?.length || 1)
61
+ </script>
62
+
63
+ <style scoped>
64
+ @layer components {
65
+ .form-slider {
66
+ position: relative;
67
+ display: flex;
68
+ align-items: center;
69
+ user-select: none;
70
+ touch-action: none;
71
+
72
+ &[data-orientation='horizontal'] {
73
+ inline-size: 100%;
74
+ block-size: var(--slider-thumb-size);
75
+ }
76
+
77
+ &[data-orientation='vertical'] {
78
+ flex-direction: column;
79
+ inline-size: var(--slider-thumb-size);
80
+ block-size: 100%;
81
+ }
82
+
83
+ &[data-disabled] {
84
+ opacity: 0.5;
85
+ cursor: not-allowed;
86
+ }
87
+ }
88
+
89
+ .form-slider-track {
90
+ position: relative;
91
+ flex-grow: 1;
92
+ background: var(--slider-track-background);
93
+ border-radius: var(--slider-track-radius);
94
+
95
+ &[data-orientation='horizontal'] {
96
+ block-size: var(--slider-track-size);
97
+ inline-size: 100%;
98
+ }
99
+
100
+ &[data-orientation='vertical'] {
101
+ inline-size: var(--slider-track-size);
102
+ block-size: 100%;
103
+ }
104
+ }
105
+
106
+ .form-slider-range {
107
+ position: absolute;
108
+ background: var(--slider-range-background);
109
+ border-radius: var(--slider-track-radius);
110
+
111
+ &[data-orientation='horizontal'] {
112
+ block-size: 100%;
113
+ }
114
+
115
+ &[data-orientation='vertical'] {
116
+ inline-size: 100%;
117
+ }
118
+ }
119
+
120
+ .form-slider-thumb {
121
+ all: unset;
122
+ display: block;
123
+ inline-size: var(--slider-thumb-size);
124
+ block-size: var(--slider-thumb-size);
125
+ border-radius: var(--slider-thumb-radius);
126
+ background: var(--slider-thumb-background);
127
+ box-shadow: var(--border-shadow);
128
+ transition:
129
+ box-shadow var(--speed),
130
+ background var(--speed);
131
+
132
+ &:is(:hover, :focus) {
133
+ box-shadow: var(--border-shadow-highlight);
134
+ }
135
+
136
+ &:focus-visible {
137
+ outline: 2px solid var(--primary);
138
+ outline-offset: 2px;
139
+ }
140
+ }
141
+ }
142
+ </style>
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <label class="form-switch">
3
+ <SwitchRoot
4
+ v-model="model"
5
+ :disabled="disabled"
6
+ :name="name"
7
+ :value="value"
8
+ :required="required"
9
+ class="form-switch-button"
10
+ >
11
+ <SwitchThumb class="form-switch-thumb" />
12
+ </SwitchRoot>
13
+ <span v-if="$slots.default"><slot /></span>
14
+ </label>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { SwitchRoot, SwitchThumb } from 'reka-ui'
19
+
20
+ const model = defineModel<boolean>()
21
+
22
+ defineProps({
23
+ disabled: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ name: {
28
+ type: String,
29
+ default: undefined,
30
+ },
31
+ value: {
32
+ type: String,
33
+ default: 'on',
34
+ },
35
+ required: {
36
+ type: Boolean,
37
+ default: false,
38
+ },
39
+ })
40
+ </script>
41
+
42
+ <style scoped>
43
+ @layer components {
44
+ .form-switch {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: var(--size-2);
48
+ cursor: pointer;
49
+ user-select: none;
50
+
51
+ &:hover .form-switch-button {
52
+ box-shadow: 0 0 0 var(--border-width) var(--border-color-highlight);
53
+ }
54
+ }
55
+
56
+ .form-switch-button {
57
+ all: unset;
58
+ position: relative;
59
+ inline-size: var(--switch-width);
60
+ block-size: var(--switch-height);
61
+ border-radius: var(--switch-border-radius);
62
+ background: var(--switch-background);
63
+ box-shadow: var(--border-shadow);
64
+ transition:
65
+ background var(--speed),
66
+ box-shadow var(--speed);
67
+ flex-shrink: 0;
68
+
69
+ &[data-state='checked'] {
70
+ background: var(--switch-background-checked);
71
+ }
72
+
73
+ &[data-disabled] {
74
+ opacity: 0.5;
75
+ cursor: not-allowed;
76
+ }
77
+
78
+ &:focus-visible {
79
+ outline: 2px solid var(--primary);
80
+ outline-offset: 2px;
81
+ }
82
+ }
83
+
84
+ .form-switch-thumb {
85
+ display: block;
86
+ inline-size: var(--switch-thumb-size);
87
+ block-size: var(--switch-thumb-size);
88
+ border-radius: var(--switch-border-radius);
89
+ background: var(--switch-thumb-background);
90
+ transition: transform var(--speed);
91
+ transform: translateX(var(--switch-thumb-offset));
92
+
93
+ &[data-state='checked'] {
94
+ transform: translateX(
95
+ calc(
96
+ var(--switch-width) - var(--switch-thumb-size) -
97
+ var(--switch-thumb-offset)
98
+ )
99
+ );
100
+ }
101
+ }
102
+ }
103
+ </style>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <Toasts />
3
+ <ConfirmDialog />
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ import Toasts from './Toasts.vue'
8
+ import ConfirmDialog from './ConfirmDialog.vue'
9
+ </script>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <img
3
+ v-if="dataUrl"
4
+ :src="dataUrl"
5
+ :alt="seed"
6
+ class="opepicon"
7
+ />
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { ref, watchEffect } from 'vue'
12
+ import { createIcon } from '@visualizevalue/opepicons'
13
+
14
+ const props = withDefaults(
15
+ defineProps<{
16
+ seed: string
17
+ size?: number
18
+ }>(),
19
+ {
20
+ size: 64,
21
+ },
22
+ )
23
+
24
+ const dataUrl = ref<string | null>(null)
25
+ watchEffect(() => {
26
+ if (!props.seed) {
27
+ dataUrl.value = null
28
+ return
29
+ }
30
+
31
+ const canvas = createIcon({ seed: props.seed, size: props.size })
32
+ dataUrl.value = canvas.toDataURL()
33
+ })
34
+ </script>
35
+
36
+ <style scoped>
37
+ @layer components {
38
+ .opepicon {
39
+ width: var(--size-5);
40
+ height: var(--size-5);
41
+ border-radius: 50%;
42
+ object-fit: cover;
43
+ }
44
+ }
45
+ </style>