@paraxe/vue 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 (107) hide show
  1. package/dist/.loba-build.json +5 -0
  2. package/dist/composites/Accordion.d.ts +22 -0
  3. package/dist/composites/AccordionItem.d.ts +21 -0
  4. package/dist/composites/ButtonGroup.d.ts +21 -0
  5. package/dist/composites/SectionHeader.d.ts +20 -0
  6. package/dist/data/EmptyState.d.ts +22 -0
  7. package/dist/data/List.d.ts +35 -0
  8. package/dist/data/ListItem.d.ts +19 -0
  9. package/dist/data/Pagination.d.ts +17 -0
  10. package/dist/data/Table.d.ts +51 -0
  11. package/dist/elements/Badge.d.ts +19 -0
  12. package/dist/elements/Button.d.ts +33 -0
  13. package/dist/elements/Card.d.ts +21 -0
  14. package/dist/elements/Image.d.ts +13 -0
  15. package/dist/elements/Tag.d.ts +13 -0
  16. package/dist/feedback/Alert.d.ts +27 -0
  17. package/dist/feedback/Progress.d.ts +29 -0
  18. package/dist/feedback/Skeleton.d.ts +13 -0
  19. package/dist/feedback/Toast.d.ts +33 -0
  20. package/dist/forms/Checkbox.d.ts +27 -0
  21. package/dist/forms/Choice.d.ts +19 -0
  22. package/dist/forms/ChoiceGroup.d.ts +32 -0
  23. package/dist/forms/FormField.d.ts +29 -0
  24. package/dist/forms/Input.d.ts +29 -0
  25. package/dist/forms/Radio.d.ts +26 -0
  26. package/dist/forms/Select.d.ts +28 -0
  27. package/dist/forms/Switch.d.ts +24 -0
  28. package/dist/forms/Textarea.d.ts +24 -0
  29. package/dist/index.d.ts +47 -0
  30. package/dist/index.js +1888 -0
  31. package/dist/navigation/Breadcrumb.d.ts +22 -0
  32. package/dist/navigation/Breadcrumbs.d.ts +18 -0
  33. package/dist/navigation/Sidebar.d.ts +22 -0
  34. package/dist/navigation/SidebarGroup.d.ts +18 -0
  35. package/dist/navigation/SidebarItem.d.ts +28 -0
  36. package/dist/navigation/Tab.d.ts +19 -0
  37. package/dist/navigation/Tabs.d.ts +22 -0
  38. package/dist/overlays/Dialog.d.ts +26 -0
  39. package/dist/overlays/Drawer.d.ts +28 -0
  40. package/dist/overlays/Popover.d.ts +20 -0
  41. package/dist/overlays/Tooltip.d.ts +21 -0
  42. package/dist/primitives/Container.d.ts +19 -0
  43. package/dist/primitives/Divider.d.ts +3 -0
  44. package/dist/primitives/Grid.d.ts +25 -0
  45. package/dist/primitives/Section.d.ts +13 -0
  46. package/dist/primitives/Stack.d.ts +21 -0
  47. package/dist/typography/Eyebrow.d.ts +13 -0
  48. package/dist/typography/Heading.d.ts +19 -0
  49. package/dist/typography/Label.d.ts +24 -0
  50. package/dist/typography/Text.d.ts +22 -0
  51. package/doc.md +527 -0
  52. package/package.json +29 -0
  53. package/src/composites/Accordion.vue +60 -0
  54. package/src/composites/AccordionItem.vue +66 -0
  55. package/src/composites/ButtonGroup.vue +27 -0
  56. package/src/composites/SectionHeader.vue +23 -0
  57. package/src/data/EmptyState.vue +40 -0
  58. package/src/data/List.vue +125 -0
  59. package/src/data/ListItem.vue +97 -0
  60. package/src/data/Pagination.vue +254 -0
  61. package/src/data/Table.vue +382 -0
  62. package/src/elements/Avatar.vue +0 -0
  63. package/src/elements/Badge.vue +30 -0
  64. package/src/elements/Button.vue +56 -0
  65. package/src/elements/Card.vue +34 -0
  66. package/src/elements/Icon.vue +0 -0
  67. package/src/elements/Image.vue +36 -0
  68. package/src/elements/Tag.vue +10 -0
  69. package/src/env.d.ts +8 -0
  70. package/src/feedback/Alert.vue +63 -0
  71. package/src/feedback/Progress.vue +95 -0
  72. package/src/feedback/Skeleton.vue +43 -0
  73. package/src/feedback/Toast.vue +141 -0
  74. package/src/forms/Checkbox.vue +54 -0
  75. package/src/forms/Choice.vue +82 -0
  76. package/src/forms/ChoiceGroup.vue +130 -0
  77. package/src/forms/FormField.vue +55 -0
  78. package/src/forms/Input.vue +54 -0
  79. package/src/forms/Radio.vue +64 -0
  80. package/src/forms/Select.vue +43 -0
  81. package/src/forms/Switch.vue +57 -0
  82. package/src/forms/Textarea.vue +54 -0
  83. package/src/index.ts +47 -0
  84. package/src/navigation/Breadcrumb.vue +59 -0
  85. package/src/navigation/Breadcrumbs.vue +30 -0
  86. package/src/navigation/Menu.vue +0 -0
  87. package/src/navigation/Sidebar.vue +35 -0
  88. package/src/navigation/SidebarGroup.vue +34 -0
  89. package/src/navigation/SidebarItem.vue +137 -0
  90. package/src/navigation/Tab.vue +78 -0
  91. package/src/navigation/Tabs.vue +68 -0
  92. package/src/overlays/Dialog.vue +193 -0
  93. package/src/overlays/Drawer.vue +200 -0
  94. package/src/overlays/Popover.vue +106 -0
  95. package/src/overlays/Tooltip.vue +69 -0
  96. package/src/primitives/Container.vue +24 -0
  97. package/src/primitives/Divider.vue +6 -0
  98. package/src/primitives/Grid.vue +36 -0
  99. package/src/primitives/Section.vue +8 -0
  100. package/src/primitives/Stack.vue +28 -0
  101. package/src/typography/Eyebrow.vue +9 -0
  102. package/src/typography/Heading.vue +27 -0
  103. package/src/typography/Label.vue +34 -0
  104. package/src/typography/Text.vue +38 -0
  105. package/tsconfig.json +17 -0
  106. package/tsconfig.tsbuildinfo +1 -0
  107. package/vite.config.ts +30 -0
@@ -0,0 +1,382 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ computed,
4
+ ref,
5
+ } from "vue";
6
+
7
+ export interface TableColumn<
8
+ T = unknown,
9
+ > {
10
+ key: string;
11
+ label: string;
12
+ sortable?: boolean;
13
+ width?: string;
14
+ align?: "start" | "center" | "end";
15
+ }
16
+
17
+ export interface TableProps<
18
+ T = unknown,
19
+ > {
20
+ columns: TableColumn<T>[];
21
+ rows: T[];
22
+ rowKey?: string;
23
+ sortable?: boolean;
24
+ selectable?: boolean;
25
+ multiple?: boolean;
26
+ loading?: boolean;
27
+ }
28
+
29
+ const props = withDefaults(
30
+ defineProps<TableProps>(),
31
+ {
32
+ rowKey: "id",
33
+ sortable: false,
34
+ selectable: false,
35
+ multiple: false,
36
+ loading: false,
37
+ },
38
+ );
39
+
40
+ const emit = defineEmits<{
41
+ "update:selectedRows": [
42
+ rows: unknown[],
43
+ ];
44
+
45
+ sort: [
46
+ payload: {
47
+ key: string;
48
+ direction: "asc" | "desc";
49
+ },
50
+ ];
51
+ }>();
52
+
53
+ const sortKey = ref<string | null>(
54
+ null,
55
+ );
56
+
57
+ const sortDirection = ref<
58
+ "asc" | "desc"
59
+ >("asc");
60
+
61
+ const selectedKeys = ref<
62
+ Set<string | number>
63
+ >(new Set());
64
+
65
+ function getRowValue(
66
+ row: unknown,
67
+ key: string,
68
+ ) {
69
+ if (
70
+ typeof row !== "object" ||
71
+ row === null
72
+ ) {
73
+ return undefined;
74
+ }
75
+
76
+ return (
77
+ row as Record<
78
+ string,
79
+ unknown
80
+ >
81
+ )[key];
82
+ }
83
+
84
+ function getRowKey(
85
+ row: unknown,
86
+ ): string | number {
87
+ const value = getRowValue(
88
+ row,
89
+ props.rowKey,
90
+ );
91
+
92
+ if (
93
+ typeof value === "string" ||
94
+ typeof value === "number"
95
+ ) {
96
+ return value;
97
+ }
98
+
99
+ return props.rows.indexOf(row);
100
+ }
101
+
102
+ function isSelected(
103
+ row: unknown,
104
+ ) {
105
+ return selectedKeys.value.has(
106
+ getRowKey(row),
107
+ );
108
+ }
109
+
110
+ const sortedRows = computed(() => {
111
+ if (
112
+ !props.sortable ||
113
+ !sortKey.value
114
+ ) {
115
+ return props.rows;
116
+ }
117
+
118
+ const key = sortKey.value;
119
+ const direction =
120
+ sortDirection.value;
121
+
122
+ return [...props.rows].sort(
123
+ (a, b) => {
124
+ const aValue =
125
+ getRowValue(a, key);
126
+ const bValue =
127
+ getRowValue(b, key);
128
+
129
+ if (
130
+ aValue === bValue
131
+ ) {
132
+ return 0;
133
+ }
134
+
135
+ if (
136
+ aValue === undefined ||
137
+ aValue === null
138
+ ) {
139
+ return 1;
140
+ }
141
+
142
+ if (
143
+ bValue === undefined ||
144
+ bValue === null
145
+ ) {
146
+ return -1;
147
+ }
148
+
149
+ if (
150
+ typeof aValue === "number" &&
151
+ typeof bValue === "number"
152
+ ) {
153
+ return direction === "asc"
154
+ ? aValue - bValue
155
+ : bValue - aValue;
156
+ }
157
+
158
+ const result =
159
+ String(aValue).localeCompare(
160
+ String(bValue),
161
+ undefined,
162
+ {
163
+ numeric: true,
164
+ sensitivity: "base",
165
+ },
166
+ );
167
+
168
+ return direction === "asc"
169
+ ? result
170
+ : -result;
171
+ },
172
+ );
173
+ });
174
+
175
+ function toggleSort(
176
+ column: TableColumn,
177
+ ) {
178
+ if (
179
+ !props.sortable ||
180
+ !column.sortable
181
+ ) {
182
+ return;
183
+ }
184
+
185
+ if (sortKey.value !== column.key) {
186
+ sortKey.value = column.key;
187
+ sortDirection.value = "asc";
188
+ } else {
189
+ sortDirection.value =
190
+ sortDirection.value === "asc"
191
+ ? "desc"
192
+ : "asc";
193
+ }
194
+
195
+ emit("sort", {
196
+ key: column.key,
197
+ direction:
198
+ sortDirection.value,
199
+ });
200
+ }
201
+
202
+ function toggleRowSelection(
203
+ row: unknown,
204
+ ) {
205
+ if (!props.selectable) {
206
+ return;
207
+ }
208
+
209
+ const key = getRowKey(row);
210
+
211
+ const next = new Set(
212
+ selectedKeys.value,
213
+ );
214
+
215
+ if (props.multiple) {
216
+ if (next.has(key)) {
217
+ next.delete(key);
218
+ } else {
219
+ next.add(key);
220
+ }
221
+ } else {
222
+ next.clear();
223
+ next.add(key);
224
+ }
225
+
226
+ selectedKeys.value = next;
227
+
228
+ emit(
229
+ "update:selectedRows",
230
+ props.rows.filter((item) =>
231
+ next.has(getRowKey(item)),
232
+ ),
233
+ );
234
+ }
235
+
236
+ function sortIndicator(
237
+ column: TableColumn,
238
+ ) {
239
+ if (
240
+ sortKey.value !== column.key
241
+ ) {
242
+ return "";
243
+ }
244
+
245
+ return sortDirection.value ===
246
+ "asc"
247
+ ? "↑"
248
+ : "↓";
249
+ }
250
+
251
+ function cellClass(
252
+ column: TableColumn,
253
+ ) {
254
+ return {
255
+ [`table-cell--${column.align ?? "start"}`]:
256
+ true,
257
+ };
258
+ }
259
+
260
+ function isSorted(
261
+ column: TableColumn,
262
+ ) {
263
+ return (
264
+ sortKey.value === column.key
265
+ );
266
+ }
267
+ </script>
268
+
269
+ <template>
270
+ <div class="table">
271
+ <table>
272
+ <thead>
273
+ <tr>
274
+ <th
275
+ v-for="column in columns"
276
+ :key="column.key"
277
+ :style="{
278
+ width: column.width,
279
+ }"
280
+ :class="[
281
+ cellClass(column),
282
+ {
283
+ 'table-header--sortable':
284
+ sortable &&
285
+ column.sortable,
286
+
287
+ 'table-header--sorted':
288
+ isSorted(column),
289
+ },
290
+ ]"
291
+ :tabindex="
292
+ sortable &&
293
+ column.sortable
294
+ ? 0
295
+ : undefined
296
+ "
297
+ :aria-sort="
298
+ isSorted(column)
299
+ ? sortDirection ===
300
+ 'asc'
301
+ ? 'ascending'
302
+ : 'descending'
303
+ : undefined
304
+ "
305
+ @click="
306
+ toggleSort(column)
307
+ "
308
+ @keydown.enter="
309
+ toggleSort(column)
310
+ "
311
+ @keydown.space.prevent="
312
+ toggleSort(column)
313
+ "
314
+ >
315
+ <span>
316
+ {{ column.label }}
317
+ </span>
318
+
319
+ <span
320
+ v-if="
321
+ sortable &&
322
+ column.sortable
323
+ "
324
+ aria-hidden="true"
325
+ >
326
+ {{
327
+ sortIndicator(column)
328
+ }}
329
+ </span>
330
+ </th>
331
+ </tr>
332
+ </thead>
333
+
334
+ <tbody>
335
+ <tr
336
+ v-for="row in sortedRows"
337
+ :key="getRowKey(row)"
338
+ :class="{
339
+ 'table-row--selected':
340
+ isSelected(row),
341
+ }"
342
+ @click="
343
+ selectable &&
344
+ toggleRowSelection(row)
345
+ "
346
+ >
347
+ <td
348
+ v-for="column in columns"
349
+ :key="column.key"
350
+ :class="
351
+ cellClass(column)
352
+ "
353
+ >
354
+ <slot
355
+ :name="`cell-${column.key}`"
356
+ :row="row"
357
+ :value="
358
+ getRowValue(
359
+ row,
360
+ column.key,
361
+ )
362
+ "
363
+ >
364
+ {{
365
+ getRowValue(
366
+ row,
367
+ column.key,
368
+ )
369
+ }}
370
+ </slot>
371
+ </td>
372
+ </tr>
373
+ </tbody>
374
+ </table>
375
+
376
+ <div
377
+ v-if="loading"
378
+ class="table-loading"
379
+ aria-hidden="true"
380
+ />
381
+ </div>
382
+ </template>
File without changes
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export type BadgeVariant =
5
+ | "default"
6
+ | "success"
7
+ | "warning"
8
+ | "danger"
9
+ | "info"
10
+ | "brand";
11
+
12
+ interface Props {
13
+ variant?: BadgeVariant;
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ variant: "default",
18
+ });
19
+
20
+ const badgeClasses = computed(() => ({
21
+ "badge": true,
22
+ [`badge-${props.variant}`]: true,
23
+ }));
24
+ </script>
25
+
26
+ <template>
27
+ <span :class="badgeClasses">
28
+ <slot />
29
+ </span>
30
+ </template>
@@ -0,0 +1,56 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ import type {
5
+ ButtonVariant,
6
+ ButtonSize,
7
+ ButtonWidth,
8
+ ButtonIconPosition,
9
+ } from "@paraxe/core";
10
+
11
+ interface Props {
12
+ variant?: ButtonVariant;
13
+ size?: ButtonSize;
14
+ width?: ButtonWidth;
15
+ iconPosition?: ButtonIconPosition;
16
+ disabled?: boolean;
17
+ loading?: boolean;
18
+ }
19
+
20
+ const props = withDefaults(defineProps<Props>(),
21
+ {
22
+ variant: "primary",
23
+ size: "medium",
24
+ width: "auto",
25
+ iconPosition: "leading",
26
+ disabled: false,
27
+ loading: false,
28
+ }
29
+ )
30
+
31
+ const emit = defineEmits<{
32
+ activate: [];
33
+ }>()
34
+
35
+ const sizeClasses: Record<ButtonSize, string> = {
36
+ small: "btn-sm",
37
+ medium: "btn-md",
38
+ large: "btn-lg",
39
+ };
40
+
41
+ const buttonClasses = computed(() => [
42
+ `btn-${props.variant}`,
43
+ sizeClasses[props.size],
44
+ props.width === "full" ? "btn-full" : "",
45
+ ]);
46
+
47
+ </script>
48
+ <template>
49
+ <button
50
+ class="btn"
51
+ :class="buttonClasses"
52
+ :disabled="props.disabled || props.loading"
53
+ @click="emit('activate')">
54
+ <slot />
55
+ </button>
56
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export type CardVariant =
5
+ | "default"
6
+ | "outlined"
7
+ | "elevated"
8
+ | "interactive"
9
+ | "selected";
10
+
11
+ export interface Props {
12
+ variant?: CardVariant;
13
+ as?: string;
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ variant: "default",
18
+ as: "div",
19
+ });
20
+
21
+ const cardClasses = computed(() => [
22
+ "card",
23
+ `card-${props.variant}`,
24
+ ]);
25
+ </script>
26
+
27
+ <template>
28
+ <component
29
+ :is="props.as"
30
+ :class="cardClasses"
31
+ >
32
+ <slot />
33
+ </component>
34
+ </template>
File without changes
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import type {
3
+ ImageAspectRatio,
4
+ ImageFit,
5
+ } from "@paraxe/core";
6
+
7
+ interface Props {
8
+ src: string;
9
+ alt: string;
10
+ fit?: ImageFit;
11
+ aspectRatio?: ImageAspectRatio;
12
+ }
13
+
14
+ const props = withDefaults(defineProps<Props>(), {
15
+ fit: "cover",
16
+ aspectRatio: "auto",
17
+ });
18
+ </script>
19
+
20
+ <template>
21
+ <div
22
+ class="media"
23
+ :class="{
24
+ 'media-square': props.aspectRatio === 'square',
25
+ 'media-video': props.aspectRatio === 'video',
26
+ 'media-portrait': props.aspectRatio === 'portrait',
27
+ 'media-wide': props.aspectRatio === 'wide',
28
+ 'media-contain': props.fit === 'contain',
29
+ }"
30
+ >
31
+ <img
32
+ :src="props.src"
33
+ :alt="props.alt"
34
+ />
35
+ </div>
36
+ </template>
@@ -0,0 +1,10 @@
1
+ <script setup lang="ts">
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <span class="tag">
7
+ <slot />
8
+ </span>
9
+ </template>
10
+
package/src/env.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ // packages/vue/src/env.d.ts
2
+ declare module "*.vue" {
3
+ import type { DefineComponent } from "vue";
4
+
5
+ const component: DefineComponent<{}, {}, any>;
6
+ export default component;
7
+ }
8
+ declare module "*.css";
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ type AlertVariant =
5
+ | "info"
6
+ | "success"
7
+ | "warning"
8
+ | "danger";
9
+
10
+ interface Props {
11
+ variant?: AlertVariant;
12
+ dismissible?: boolean;
13
+ }
14
+
15
+ const props = withDefaults(
16
+ defineProps<Props>(),
17
+ {
18
+ variant: "info",
19
+ dismissible: false,
20
+ },
21
+ );
22
+
23
+ const emit = defineEmits<{
24
+ close: [];
25
+ }>();
26
+
27
+ const alertClasses = computed(() => ({
28
+ alert: true,
29
+ [`alert-${props.variant}`]: true,
30
+ }));
31
+
32
+ function handleClose() {
33
+ emit("close");
34
+ }
35
+ </script>
36
+
37
+ <template>
38
+ <div
39
+ :class="alertClasses"
40
+ role="alert"
41
+ >
42
+ <div class="alert-content">
43
+ <slot />
44
+
45
+ <div
46
+ v-if="$slots.actions"
47
+ class="alert-actions"
48
+ >
49
+ <slot name="actions" />
50
+ </div>
51
+ </div>
52
+
53
+ <button
54
+ v-if="dismissible"
55
+ class="alert-close"
56
+ type="button"
57
+ aria-label="Dismiss alert"
58
+ @click="handleClose"
59
+ >
60
+ ×
61
+ </button>
62
+ </div>
63
+ </template>
@@ -0,0 +1,95 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ type ProgressVariant =
5
+ | "default"
6
+ | "success"
7
+ | "warning"
8
+ | "danger";
9
+
10
+ interface Props {
11
+ value?: number;
12
+ max?: number;
13
+ indeterminate?: boolean;
14
+ variant?: ProgressVariant;
15
+ showValue?: boolean;
16
+ }
17
+
18
+ const props = withDefaults(
19
+ defineProps<Props>(),
20
+ {
21
+ value: 0,
22
+ max: 100,
23
+ indeterminate: false,
24
+ variant: "default",
25
+ showValue: false,
26
+ },
27
+ );
28
+
29
+ const percentage = computed(() => {
30
+ if (props.max <= 0) {
31
+ return 0;
32
+ }
33
+
34
+ return Math.min(
35
+ 100,
36
+ Math.max(
37
+ 0,
38
+ (props.value / props.max) * 100,
39
+ ),
40
+ );
41
+ });
42
+
43
+ const progressClasses = computed(() => ({
44
+ progress: true,
45
+ [`progress--${props.variant}`]:
46
+ true,
47
+ "progress--indeterminate":
48
+ props.indeterminate,
49
+ }));
50
+ </script>
51
+
52
+ <template>
53
+ <div
54
+ :class="progressClasses"
55
+ role="progressbar"
56
+ :aria-valuemin="indeterminate ? undefined : 0"
57
+ :aria-valuemax="indeterminate ? undefined : max"
58
+ :aria-valuenow="
59
+ indeterminate
60
+ ? undefined
61
+ : value
62
+ "
63
+ >
64
+ <div class="progress-track">
65
+ <div
66
+ class="progress-value"
67
+ :style="
68
+ indeterminate
69
+ ? undefined
70
+ : {
71
+ width: `${percentage}%`,
72
+ }
73
+ "
74
+ />
75
+ </div>
76
+
77
+ <div
78
+ v-if="showValue"
79
+ class="progress-label"
80
+ >
81
+ <span>
82
+ <slot />
83
+ </span>
84
+
85
+ <span>
86
+ {{ Math.round(percentage) }}%
87
+ </span>
88
+ </div>
89
+
90
+ <slot
91
+ v-else
92
+ name="label"
93
+ />
94
+ </div>
95
+ </template>