@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,43 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ type SkeletonVariant =
5
+ | "text"
6
+ | "heading"
7
+ | "avatar"
8
+ | "circle"
9
+ | "button"
10
+ | "default";
11
+
12
+ interface Props {
13
+ variant?: SkeletonVariant;
14
+ width?: string;
15
+ height?: string;
16
+ }
17
+
18
+ const props = withDefaults(
19
+ defineProps<Props>(),
20
+ {
21
+ variant: "default",
22
+ width: undefined,
23
+ height: undefined,
24
+ },
25
+ );
26
+
27
+ const skeletonClasses = computed(() => ({
28
+ skeleton: true,
29
+ [`skeleton--${props.variant}`]:
30
+ props.variant !== "default",
31
+ }));
32
+ </script>
33
+
34
+ <template>
35
+ <div
36
+ :class="skeletonClasses"
37
+ :style="{
38
+ width: props.width,
39
+ height: props.height,
40
+ }"
41
+ aria-hidden="true"
42
+ />
43
+ </template>
@@ -0,0 +1,141 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ onBeforeUnmount,
4
+ ref,
5
+ watch,
6
+ } from "vue";
7
+
8
+ type ToastVariant =
9
+ | "info"
10
+ | "success"
11
+ | "warning"
12
+ | "danger";
13
+
14
+ interface Props {
15
+ modelValue?: boolean;
16
+ title?: string;
17
+ variant?: ToastVariant;
18
+ duration?: number;
19
+ dismissible?: boolean;
20
+ }
21
+
22
+ const props = withDefaults(
23
+ defineProps<Props>(),
24
+ {
25
+ modelValue: false,
26
+ title: undefined,
27
+ variant: "info",
28
+ duration: 4000,
29
+ dismissible: true,
30
+ },
31
+ );
32
+
33
+ const emit = defineEmits<{
34
+ "update:modelValue": [
35
+ value: boolean,
36
+ ];
37
+
38
+ close: [];
39
+ }>();
40
+
41
+ const visible = ref(
42
+ props.modelValue,
43
+ );
44
+
45
+ let timer:
46
+ | ReturnType<typeof setTimeout>
47
+ | undefined;
48
+
49
+ function clearTimer() {
50
+ if (timer) {
51
+ clearTimeout(timer);
52
+ timer = undefined;
53
+ }
54
+ }
55
+
56
+ function close() {
57
+ clearTimer();
58
+
59
+ visible.value = false;
60
+
61
+ emit(
62
+ "update:modelValue",
63
+ false,
64
+ );
65
+
66
+ emit("close");
67
+ }
68
+
69
+ function startTimer() {
70
+ clearTimer();
71
+
72
+ if (
73
+ props.duration <= 0 ||
74
+ !props.modelValue
75
+ ) {
76
+ return;
77
+ }
78
+
79
+ timer = setTimeout(() => {
80
+ close();
81
+ }, props.duration);
82
+ }
83
+
84
+ watch(
85
+ () => props.modelValue,
86
+ (value) => {
87
+ visible.value = value;
88
+
89
+ if (value) {
90
+ startTimer();
91
+ } else {
92
+ clearTimer();
93
+ }
94
+ },
95
+ {
96
+ immediate: true,
97
+ },
98
+ );
99
+
100
+ onBeforeUnmount(() => {
101
+ clearTimer();
102
+ });
103
+ </script>
104
+
105
+ <template>
106
+ <Teleport to="body">
107
+ <div
108
+ v-if="visible"
109
+ class="toast"
110
+ :class="{
111
+ 'toast--visible': visible,
112
+ [`toast-${variant}`]: true,
113
+ }"
114
+ role="status"
115
+ aria-live="polite"
116
+ >
117
+ <div class="toast-content">
118
+ <div
119
+ v-if="title"
120
+ class="toast-title"
121
+ >
122
+ {{ title }}
123
+ </div>
124
+
125
+ <div class="toast-message">
126
+ <slot />
127
+ </div>
128
+ </div>
129
+
130
+ <button
131
+ v-if="dismissible"
132
+ class="toast-close"
133
+ type="button"
134
+ aria-label="Dismiss notification"
135
+ @click="close"
136
+ >
137
+ ×
138
+ </button>
139
+ </div>
140
+ </Teleport>
141
+ </template>
@@ -0,0 +1,54 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ interface Props {
5
+ value?: boolean;
6
+ disabled?: boolean;
7
+ name?: string;
8
+ required?: boolean;
9
+ }
10
+
11
+ const props = withDefaults(defineProps<Props>(), {
12
+ value: false,
13
+ disabled: false,
14
+ required: false,
15
+ });
16
+
17
+ const emit = defineEmits<{
18
+ change: [value: boolean];
19
+ }>();
20
+
21
+ const checkboxClasses = computed(() => ({
22
+ checkbox: true,
23
+ "checkbox--checked": props.value,
24
+ "checkbox--disabled": props.disabled,
25
+ }));
26
+ </script>
27
+
28
+ <template>
29
+ <label :class="checkboxClasses">
30
+ <input
31
+ class="checkbox-input"
32
+ type="checkbox"
33
+ :name="props.name"
34
+ :checked="props.value"
35
+ :disabled="props.disabled"
36
+ :required="props.required"
37
+ @change="
38
+ emit(
39
+ 'change',
40
+ ($event.target as HTMLInputElement).checked,
41
+ )
42
+ "
43
+ />
44
+
45
+ <span
46
+ class="checkbox-control"
47
+ aria-hidden="true"
48
+ />
49
+
50
+ <span class="checkbox-label">
51
+ <slot />
52
+ </span>
53
+ </label>
54
+ </template>
@@ -0,0 +1,82 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ computed,
4
+ inject,
5
+ } from "vue";
6
+
7
+ export interface ChoiceProps {
8
+ value: string | number;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ const props = withDefaults(
13
+ defineProps<ChoiceProps>(),
14
+ {
15
+ disabled: false,
16
+ },
17
+ );
18
+
19
+ interface ChoiceGroupContext {
20
+ multiple: boolean;
21
+ disabled: boolean;
22
+
23
+ isSelected: (
24
+ value: string | number,
25
+ ) => boolean;
26
+
27
+ toggleChoice: (
28
+ value: string | number,
29
+ ) => void;
30
+ }
31
+
32
+ const injectedGroup = inject<ChoiceGroupContext>(
33
+ "loba-choice-group",
34
+ );
35
+
36
+ if (!injectedGroup) {
37
+ throw new Error(
38
+ "Choice must be used inside a ChoiceGroup.",
39
+ );
40
+ }
41
+
42
+ const group = injectedGroup;
43
+
44
+
45
+ const selected = computed(() =>
46
+ group.isSelected(props.value),
47
+ );
48
+
49
+ const disabled = computed(
50
+ () =>
51
+ props.disabled ||
52
+ group.disabled,
53
+ );
54
+
55
+ const classes = computed(() => ({
56
+ choice: true,
57
+ "choice--selected":
58
+ selected.value,
59
+ "choice--disabled":
60
+ disabled.value,
61
+ }));
62
+
63
+ function handleClick() {
64
+ if (disabled.value) {
65
+ return;
66
+ }
67
+
68
+ group.toggleChoice(props.value);
69
+ }
70
+ </script>
71
+
72
+ <template>
73
+ <button
74
+ type="button"
75
+ :class="classes"
76
+ :disabled="disabled"
77
+ :aria-pressed="selected"
78
+ @click="handleClick"
79
+ >
80
+ <slot />
81
+ </button>
82
+ </template>
@@ -0,0 +1,130 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ computed,
4
+ provide,
5
+ } from "vue";
6
+
7
+ export interface ChoiceGroupProps {
8
+ modelValue?:
9
+ | string
10
+ | number
11
+ | Array<string | number>
12
+ | null;
13
+
14
+ multiple?: boolean;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ export interface ChoiceGroupContext {
19
+ multiple: boolean;
20
+ disabled: boolean;
21
+
22
+ isSelected: (
23
+ value: string | number,
24
+ ) => boolean;
25
+
26
+ toggleChoice: (
27
+ value: string | number,
28
+ ) => void;
29
+ }
30
+
31
+ const props = withDefaults(
32
+ defineProps<ChoiceGroupProps>(),
33
+ {
34
+ modelValue: null,
35
+ multiple: false,
36
+ disabled: false,
37
+ },
38
+ );
39
+
40
+ const emit = defineEmits<{
41
+ "update:modelValue": [
42
+ value:
43
+ | string
44
+ | number
45
+ | Array<string | number>
46
+ | null,
47
+ ];
48
+ }>();
49
+
50
+ const classes = computed(() => ({
51
+ "choice-group": true,
52
+ "choice-group--multiple": props.multiple,
53
+ }));
54
+
55
+ const selectedValues = computed<
56
+ Array<string | number>
57
+ >(() => {
58
+ if (Array.isArray(props.modelValue)) {
59
+ return props.modelValue;
60
+ }
61
+
62
+ if (
63
+ props.modelValue === null ||
64
+ props.modelValue === undefined
65
+ ) {
66
+ return [];
67
+ }
68
+
69
+ return [props.modelValue];
70
+ });
71
+
72
+ function isSelected(
73
+ value: string | number,
74
+ ) {
75
+ return selectedValues.value.includes(
76
+ value,
77
+ );
78
+ }
79
+
80
+ function toggleChoice(
81
+ value: string | number,
82
+ ) {
83
+ if (props.disabled) {
84
+ return;
85
+ }
86
+
87
+ if (props.multiple) {
88
+ const next = new Set(
89
+ selectedValues.value,
90
+ );
91
+
92
+ if (next.has(value)) {
93
+ next.delete(value);
94
+ } else {
95
+ next.add(value);
96
+ }
97
+
98
+ emit(
99
+ "update:modelValue",
100
+ [...next],
101
+ );
102
+
103
+ return;
104
+ }
105
+
106
+ emit(
107
+ "update:modelValue",
108
+ value,
109
+ );
110
+ }
111
+
112
+ provide<ChoiceGroupContext>(
113
+ "loba-choice-group",
114
+ {
115
+ multiple: props.multiple,
116
+ disabled: props.disabled,
117
+ isSelected,
118
+ toggleChoice,
119
+ },
120
+ );
121
+ </script>
122
+
123
+ <template>
124
+ <div
125
+ :class="classes"
126
+ role="group"
127
+ >
128
+ <slot />
129
+ </div>
130
+ </template>
@@ -0,0 +1,55 @@
1
+ <script setup lang="ts">
2
+ import Label from "../typography/Label.vue";
3
+ import Text from "../typography/Text.vue";
4
+
5
+ interface Props {
6
+ id: string;
7
+ label?: string;
8
+ description?: string;
9
+ error?: string;
10
+ required?: boolean;
11
+ optional?: boolean;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ const props = withDefaults(defineProps<Props>(), {
16
+ label: undefined,
17
+ description: undefined,
18
+ error: undefined,
19
+ required: false,
20
+ optional: false,
21
+ disabled: false,
22
+ });
23
+ </script>
24
+
25
+ <template>
26
+ <div
27
+ class="form-field"
28
+ >
29
+ <Label
30
+ v-if="props.label"
31
+ :for="props.id"
32
+ :required="props.required"
33
+ :optional="props.optional"
34
+ :disabled="props.disabled"
35
+ >
36
+ {{ props.label }}
37
+ </Label>
38
+
39
+ <slot />
40
+
41
+ <Text
42
+ v-if="props.description && !props.error"
43
+ tone="muted"
44
+ >
45
+ {{ props.description }}
46
+ </Text>
47
+
48
+ <Text
49
+ v-if="props.error"
50
+ tone="accent"
51
+ >
52
+ {{ props.error }}
53
+ </Text>
54
+ </div>
55
+ </template>
@@ -0,0 +1,54 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ import type {
5
+ InputType,
6
+ } from "@paraxe/core";
7
+
8
+ interface Props {
9
+ type: InputType;
10
+ placeholder?: string;
11
+ value?: string;
12
+ required?: boolean;
13
+ disabled?: boolean;
14
+ readonly?: boolean;
15
+ error?: boolean;
16
+ success?: boolean;
17
+ }
18
+
19
+ const props = withDefaults(defineProps<Props>(), {
20
+ type: "text",
21
+ placeholder: "",
22
+ value: "",
23
+ required: false,
24
+ disabled: false,
25
+ readonly: false,
26
+ error: false,
27
+ success: false,
28
+ });
29
+
30
+ const emit = defineEmits<{
31
+ input: [value: string];
32
+ change: [value: string];
33
+ }>();
34
+
35
+ const inputClasses = computed(() => ({
36
+ "input-error": props.error,
37
+ "input-success": props.success,
38
+ }));
39
+ </script>
40
+
41
+ <template>
42
+ <input
43
+ class="input"
44
+ :class="inputClasses"
45
+ :type="props.type"
46
+ :placeholder="props.placeholder"
47
+ :value="props.value"
48
+ :required="props.required"
49
+ :disabled="props.disabled"
50
+ :readonly="props.readonly"
51
+ @input="emit('input', ($event.target as HTMLInputElement).value)"
52
+ @change="emit('change', ($event.target as HTMLInputElement).value)"
53
+ />
54
+ </template>
@@ -0,0 +1,64 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export interface RadioProps {
5
+ modelValue?: string | number | null;
6
+ value: string | number;
7
+ name: string;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ const props = withDefaults(
12
+ defineProps<RadioProps>(),
13
+ {
14
+ modelValue: null,
15
+ disabled: false,
16
+ },
17
+ );
18
+
19
+ const emit = defineEmits<{
20
+ "update:modelValue": [
21
+ value: string | number,
22
+ ];
23
+ }>();
24
+
25
+ const checked = computed(
26
+ () => props.modelValue === props.value,
27
+ );
28
+
29
+ const classes = computed(() => ({
30
+ radio: true,
31
+ "radio--checked": checked.value,
32
+ "radio--disabled": props.disabled,
33
+ }));
34
+
35
+ function handleChange() {
36
+ emit(
37
+ "update:modelValue",
38
+ props.value,
39
+ );
40
+ }
41
+ </script>
42
+
43
+ <template>
44
+ <label :class="classes">
45
+ <input
46
+ type="radio"
47
+ :name="name"
48
+ :value="value"
49
+ :checked="checked"
50
+ :disabled="disabled"
51
+ class="sr-only"
52
+ @change="handleChange"
53
+ />
54
+
55
+ <span
56
+ class="radio-control"
57
+ aria-hidden="true"
58
+ />
59
+
60
+ <span>
61
+ <slot />
62
+ </span>
63
+ </label>
64
+ </template>
@@ -0,0 +1,43 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ interface Props {
5
+ value?: string;
6
+ disabled?: boolean;
7
+ error?: boolean;
8
+ success?: boolean;
9
+ }
10
+
11
+ const props = withDefaults(defineProps<Props>(), {
12
+ value: "",
13
+ disabled: false,
14
+ error: false,
15
+ success: false,
16
+ });
17
+
18
+ const emit = defineEmits<{
19
+ change: [value: string];
20
+ }>();
21
+
22
+ const selectClasses = computed(() => ({
23
+ "input-error": props.error,
24
+ "input-success": props.success,
25
+ }));
26
+
27
+ function handleChange(event: Event) {
28
+ const target = event.target as HTMLSelectElement;
29
+ emit("change", target.value);
30
+ }
31
+ </script>
32
+
33
+ <template>
34
+ <select
35
+ class="select"
36
+ :class="selectClasses"
37
+ :value="props.value"
38
+ :disabled="props.disabled"
39
+ @change="handleChange"
40
+ >
41
+ <slot />
42
+ </select>
43
+ </template>
@@ -0,0 +1,57 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export interface SwitchProps {
5
+ modelValue?: boolean;
6
+ disabled?: boolean;
7
+ }
8
+
9
+ const props = withDefaults(
10
+ defineProps<SwitchProps>(),
11
+ {
12
+ modelValue: false,
13
+ disabled: false,
14
+ },
15
+ );
16
+
17
+ const emit = defineEmits<{
18
+ "update:modelValue": [value: boolean];
19
+ }>();
20
+
21
+ const classes = computed(() => ({
22
+ switch: true,
23
+ "switch--checked": props.modelValue,
24
+ "switch--disabled": props.disabled,
25
+ }));
26
+
27
+ function handleChange(event: Event) {
28
+ const input = event.target as HTMLInputElement;
29
+
30
+ emit(
31
+ "update:modelValue",
32
+ input.checked,
33
+ );
34
+ }
35
+ </script>
36
+
37
+ <template>
38
+ <label :class="classes">
39
+ <input
40
+ type="checkbox"
41
+ role="switch"
42
+ :checked="modelValue"
43
+ :disabled="disabled"
44
+ class="sr-only"
45
+ @change="handleChange"
46
+ />
47
+
48
+ <span
49
+ class="switch-control"
50
+ aria-hidden="true"
51
+ />
52
+
53
+ <span>
54
+ <slot />
55
+ </span>
56
+ </label>
57
+ </template>