@tak-ps/vue-tabler 3.87.4 → 4.1.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/CHANGELOG.md CHANGED
@@ -10,6 +10,15 @@
10
10
 
11
11
  ## Version History
12
12
 
13
+ ### v4.1.0
14
+
15
+ - :rocket: Add delete confirmation to TablerDelete
16
+
17
+ ### v4.0.0
18
+
19
+ - :rocket: Migrate to Typescript
20
+ - :rocket: Remove Hardcoded `No` prefix from TablerNone
21
+
13
22
  ### v3.87.4
14
23
 
15
24
  - :rocket: Continue iterating on adding npm Trusted Publisher
package/README.md CHANGED
@@ -1,2 +1,102 @@
1
- # vue-tabler
2
- Tabler UI components for Vue3
1
+ # Vue Tabler
2
+
3
+ <p align="center">
4
+ <a href="https://vuejs.org/">
5
+ <img src="https://img.shields.io/badge/vue-3.x-brightgreen.svg" alt="Vue 3">
6
+ </a>
7
+ <a href="https://www.npmjs.com/package/@tak-ps/vue-tabler">
8
+ <img src="https://img.shields.io/npm/v/@tak-ps/vue-tabler.svg" alt="npm version">
9
+ </a>
10
+ <a href="https://github.com/tak-ps/vue-tabler/blob/main/LICENSE">
11
+ <img src="https://img.shields.io/npm/l/@tak-ps/vue-tabler.svg" alt="License">
12
+ </a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <strong>A comprehensive collection of Vue 3 components based on the Tabler UI kit.</strong>
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## 🚀 Introduction
22
+
23
+ `@tak-ps/vue-tabler` brings the beautiful and responsive [Tabler](https://tabler.io/) UI kit to your Vue 3 applications. It provides a set of reusable, high-quality components designed to speed up your development process while maintaining a clean and professional look.
24
+
25
+ ## 📦 Installation
26
+
27
+ Install the package using npm:
28
+
29
+ ```bash
30
+ npm install @tak-ps/vue-tabler
31
+ ```
32
+
33
+ ## 💻 Usage
34
+
35
+ Import the components you need directly into your Vue files. All components are exported with a `Tabler` prefix to avoid conflicts.
36
+
37
+ ```vue
38
+ <script setup>
39
+ import { TablerButton, TablerAlert } from '@tak-ps/vue-tabler';
40
+ </script>
41
+
42
+ <template>
43
+ <TablerAlert title="Success!" variant="success">
44
+ Your operation was completed successfully.
45
+ </TablerAlert>
46
+
47
+ <TablerButton variant="primary" @click="doSomething">
48
+ Click Me
49
+ </TablerButton>
50
+ </template>
51
+ ```
52
+
53
+ ## 🧩 Components
54
+
55
+ ### Core Components
56
+ | Component | Description |
57
+ |-----------|-------------|
58
+ | **TablerAlert** | Display important messages and feedback. |
59
+ | **TablerBreadCrumb** | Navigation aid indicating the current page's location. |
60
+ | **TablerButton** | Standard action buttons with various styles. |
61
+ | **TablerBytes** | Utility to format byte values into human-readable strings. |
62
+ | **TablerDelete** | Specialized button/action for delete operations. |
63
+ | **TablerDropdown** | Toggleable menus for actions or navigation. |
64
+ | **TablerEpoch** | Display formatted dates and times. |
65
+ | **TablerEpochRange** | Display a range of dates/times. |
66
+ | **TablerError** | Standardized error message display. |
67
+ | **TablerHelp** | Tooltips or help text for user guidance. |
68
+ | **TablerIconButton** | Buttons designed to contain icons. |
69
+ | **TablerInlineAlert** | Contextual alerts for inline feedback. |
70
+ | **TablerList** | Display data in list format. |
71
+ | **TablerLoading** | Loading indicators and spinners. |
72
+ | **TablerMarkdown** | Render markdown content safely. |
73
+ | **TablerModal** | Dialog boxes for user interaction. |
74
+ | **TablerNone** | Placeholder component for empty states. |
75
+ | **TablerPager** | Pagination controls for lists and tables. |
76
+ | **TablerProgress** | Progress bars to indicate status. |
77
+ | **TablerRefreshButton** | A dedicated button for refresh actions. |
78
+ | **TablerSchema** | Visualization for data schemas. |
79
+ | **TablerSlidedown** | Expandable/collapsible content areas. |
80
+
81
+ ### Input Components
82
+ | Component | Description |
83
+ |-----------|-------------|
84
+ | **TablerColour** | Color picker input. |
85
+ | **TablerEnum** | Selection input for enumerated values. |
86
+ | **TablerFileInput** | File upload input. |
87
+ | **TablerInput** | Standard text and data input fields. |
88
+ | **TablerRange** | Range slider input. |
89
+ | **TablerSelect** | Dropdown selection input. |
90
+ | **TablerTimeZone** | Timezone selector. |
91
+ | **TablerToggle** | Switch/Toggle control. |
92
+
93
+ ## 🛠️ Dependencies
94
+
95
+ This library relies on the following core dependencies:
96
+ - [Vue 3](https://vuejs.org/)
97
+ - [@tabler/icons-vue](https://www.npmjs.com/package/@tabler/icons-vue)
98
+ - [showdown](https://www.npmjs.com/package/showdown) (for Markdown rendering)
99
+
100
+ ## 📄 License
101
+
102
+ This project is licensed under the [ISC License](LICENSE).
@@ -9,12 +9,12 @@
9
9
  <IconAlertTriangle
10
10
  v-if='compact'
11
11
  :size='32'
12
- :stroke='1'
12
+ stroke='1'
13
13
  />
14
14
  <IconAlertTriangle
15
15
  v-else
16
16
  :size='48'
17
- :stroke='1'
17
+ stroke='1'
18
18
  />
19
19
  </div>
20
20
 
@@ -40,13 +40,13 @@
40
40
  <IconChevronRight
41
41
  v-if='!open'
42
42
  :size='24'
43
- :stroke='1'
43
+ stroke='1'
44
44
  class='cursor-pointer'
45
45
  />
46
46
  <IconChevronDown
47
47
  v-else
48
48
  :size='24'
49
- :stroke='1'
49
+ stroke='1'
50
50
  class='cursor-pointer'
51
51
  />
52
52
  <span>Advanced</span>
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
 
64
- <script setup>
64
+ <script setup lang="ts">
65
65
  import { ref } from 'vue'
66
66
  import {
67
67
  IconAlertTriangle,
@@ -69,24 +69,19 @@ import {
69
69
  IconChevronDown,
70
70
  } from '@tabler/icons-vue'
71
71
 
72
- defineProps({
73
- title: {
74
- type: String,
75
- default: 'Generic Error'
76
- },
77
- err: {
78
- type: Error,
79
- default: new Error('Something is amiss')
80
- },
81
- compact: {
82
- type: Boolean,
83
- default: false
84
- },
85
- advanced: {
86
- type: Boolean,
87
- default: true
88
- },
89
- })
72
+ export interface AlertProps {
73
+ title?: string;
74
+ err?: Error & { body?: string };
75
+ compact?: boolean;
76
+ advanced?: boolean;
77
+ }
78
+
79
+ withDefaults(defineProps<AlertProps>(), {
80
+ title: 'Generic Error',
81
+ err: () => new Error('Something is amiss'),
82
+ compact: false,
83
+ advanced: true
84
+ });
90
85
 
91
86
  const open = ref(false)
92
87
  </script>
@@ -37,25 +37,25 @@
37
37
  </ol>
38
38
  </template>
39
39
 
40
- <script setup>
40
+ <script setup lang="ts">
41
41
  import { computed } from 'vue'
42
42
  import { useRouter, useRoute } from 'vue-router'
43
43
 
44
- const props = defineProps({
45
- normalize: {
46
- type: Boolean,
47
- default: true,
48
- description: 'Perform Title Casing on URL Components'
49
- }
50
- })
44
+ export interface BreadCrumbProps {
45
+ normalize?: boolean;
46
+ }
47
+
48
+ const props = withDefaults(defineProps<BreadCrumbProps>(), {
49
+ normalize: true
50
+ });
51
51
 
52
52
  const router = useRouter()
53
53
  const route = useRoute()
54
54
 
55
55
  const crumbs = computed(() => {
56
- return route.path.split('/').filter((crumb) => {
56
+ return route.path.split('/').filter((crumb: string) => {
57
57
  return crumb.length
58
- }).map((crumb) => {
58
+ }).map((crumb: string) => {
59
59
  if (props.normalize) {
60
60
  return `${crumb[0].toUpperCase()}${crumb.slice(1, crumb.length)}`
61
61
  } else {
@@ -8,8 +8,10 @@
8
8
  </button>
9
9
  </template>
10
10
 
11
- <script setup>
12
- const props = defineProps({
13
- disabled: Boolean
14
- })
11
+ <script setup lang="ts">
12
+ export interface ButtonProps {
13
+ disabled?: boolean;
14
+ }
15
+
16
+ const props = defineProps<ButtonProps>();
15
17
  </script>
@@ -2,18 +2,18 @@
2
2
  <span v-text='display' />
3
3
  </template>
4
4
 
5
- <script setup>
5
+ <script setup lang="ts">
6
6
  import { computed } from 'vue'
7
7
 
8
- const props = defineProps({
9
- bytes: {
10
- type: Number,
11
- required: true
12
- }
13
- })
8
+ export interface BytesProps {
9
+ bytes: number;
10
+ }
11
+
12
+ const props = defineProps<BytesProps>();
14
13
 
15
14
  const display = computed(() => {
16
15
  const i = props.bytes == 0 ? 0 : Math.floor(Math.log(props.bytes) / Math.log(1024))
16
+ // @ts-expect-error: Type checking for array indexing
17
17
  return (props.bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]
18
18
  })
19
19
  </script>
@@ -4,7 +4,7 @@
4
4
  <button
5
5
  class='btn btn-outline-danger'
6
6
  :disabled='props.disabled'
7
- @click.stop.prevent='props.disabled ? undefined : modal = true'
7
+ @click.stop.prevent='openModal'
8
8
  >
9
9
  <span v-text='props.label' />
10
10
  </button>
@@ -15,7 +15,7 @@
15
15
  :class='{
16
16
  "cursor-pointer": !props.disabled,
17
17
  }'
18
- @click.stop.prevent='props.disabled ? undefined : modal = true'
18
+ @click.stop.prevent='openModal'
19
19
  >
20
20
  <IconTrash
21
21
  :size='32'
@@ -31,11 +31,11 @@
31
31
  <TablerIconButton
32
32
  title='Delete'
33
33
  :disabled='props.disabled'
34
- @click.stop.prevent='props.disabled ? undefined : modal = true'
34
+ @click.stop.prevent='openModal'
35
35
  >
36
36
  <IconTrash
37
37
  :size='props.size'
38
- :stroke='1'
38
+ stroke='1'
39
39
  />
40
40
  </TablerIconButton>
41
41
  </template>
@@ -52,12 +52,25 @@
52
52
  Deletion Confirmation
53
53
  </div>
54
54
  <div class='modal-body text-center py-4'>
55
- Are you sure you wish to perform this deletion?
55
+ <div>Are you sure you wish to perform this deletion?</div>
56
+ <div
57
+ v-if='props.match'
58
+ class='mt-3'
59
+ >
60
+ <div class='mb-2'>
61
+ Type <span class='fw-bold'>{{ props.match }}</span> to confirm
62
+ </div>
63
+ <TablerInput
64
+ v-model='matchInput'
65
+ :placeholder='props.match'
66
+ />
67
+ </div>
56
68
  </div>
57
69
  <div class='modal-footer'>
58
70
  <div
59
71
  class='btn btn-danger'
60
- @click='deleting'
72
+ :class='{ "disabled": props.match && matchInput !== props.match }'
73
+ @click='(props.match && matchInput !== props.match) ? undefined : deleting()'
61
74
  >
62
75
  <TablerLoading
63
76
  v-if='loading'
@@ -66,7 +79,7 @@
66
79
  <template v-else>
67
80
  <IconTrash
68
81
  :size='props.size'
69
- :stroke='1'
82
+ stroke='1'
70
83
  /><span
71
84
  class='mx-2'
72
85
  v-text='props.label'
@@ -78,38 +91,44 @@
78
91
  </div>
79
92
  </template>
80
93
 
81
- <script setup>
94
+ <script setup lang="ts">
82
95
  import { ref } from 'vue'
83
96
  import TablerModal from './Modal.vue';
84
97
  import TablerIconButton from './IconButton.vue';
85
98
  import TablerLoading from './Loading.vue';
99
+ import TablerInput from './input/Input.vue';
86
100
  import {
87
101
  IconTrash
88
102
  } from '@tabler/icons-vue';
89
103
 
90
- const props = defineProps({
91
- label: {
92
- type: String,
93
- default: 'Delete'
94
- },
95
- size: {
96
- type: Number,
97
- default: 32
98
- },
99
- disabled: {
100
- type: Boolean,
101
- default: false
102
- },
103
- displaytype: {
104
- type: String,
105
- default: 'button' // Or icon
106
- }
107
- })
104
+ export interface DeleteProps {
105
+ label?: string;
106
+ size?: number;
107
+ disabled?: boolean;
108
+ displaytype?: 'button' | 'icon' | 'menu';
109
+ match?: string;
110
+ }
111
+
112
+ const props = withDefaults(defineProps<DeleteProps>(), {
113
+ label: 'Delete',
114
+ size: 32,
115
+ disabled: false,
116
+ displaytype: 'button'
117
+ });
108
118
 
109
- const emit = defineEmits(['delete'])
119
+ const emit = defineEmits<{
120
+ (e: 'delete'): void
121
+ }>()
110
122
 
111
123
  const loading = ref(false)
112
124
  const modal = ref(false)
125
+ const matchInput = ref('')
126
+
127
+ const openModal = () => {
128
+ if (props.disabled) return;
129
+ matchInput.value = '';
130
+ modal.value = true;
131
+ }
113
132
 
114
133
  const deleting = () => {
115
134
  loading.value = true;
@@ -29,33 +29,22 @@
29
29
  </div>
30
30
  </template>
31
31
 
32
- <script setup>
32
+ <script setup lang="ts">
33
33
  import { ref, computed } from 'vue';
34
34
  import {
35
35
  IconSettings
36
36
  } from '@tabler/icons-vue';
37
37
 
38
- const props = defineProps({
39
- width: {
40
- type: Number,
41
- default: 200
42
- },
43
- autoclose: {
44
- type: String,
45
- default: 'true'
46
- },
47
- position: {
48
- type: String,
49
- default: 'bottom-end',
50
- validator: (value) => {
51
- const validPositions = [
52
- 'bottom', 'bottom-start', 'bottom-end',
53
- 'top', 'top-start', 'top-end',
54
- 'left', 'right'
55
- ];
56
- return validPositions.includes(value);
57
- }
58
- }
38
+ export interface DropdownProps {
39
+ width?: number | string;
40
+ autoclose?: string;
41
+ position?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' | 'left' | 'right';
42
+ }
43
+
44
+ const props = withDefaults(defineProps<DropdownProps>(), {
45
+ width: 200,
46
+ autoclose: 'true',
47
+ position: 'bottom-end'
59
48
  });
60
49
 
61
50
  const id = ref('tabler-dropdown-' + Math.random().toString(36).substr(2, 9) + '-' + Date.now().toString(36));
@@ -2,21 +2,19 @@
2
2
  <span v-text='display' />
3
3
  </template>
4
4
 
5
- <script setup>
5
+ <script setup lang="ts">
6
6
  import { computed } from 'vue'
7
7
 
8
- const props = defineProps({
9
- date: {
10
- type: [Number, String],
11
- required: true
12
- },
13
- format: {
14
- type: String,
15
- default: 'Human'
16
- }
17
- })
8
+ export interface EpochProps {
9
+ date: number | string;
10
+ format?: string;
11
+ }
12
+
13
+ const props = withDefaults(defineProps<EpochProps>(), {
14
+ format: 'Human'
15
+ });
18
16
 
19
- const suffix = {
17
+ const suffix: Record<string, string> = {
20
18
  1: 'st',
21
19
  2: 'nd',
22
20
  3: 'rd'
@@ -2,25 +2,20 @@
2
2
  <span v-text='display' />
3
3
  </template>
4
4
 
5
- <script setup>
5
+ <script setup lang="ts">
6
6
  import { computed } from 'vue'
7
7
 
8
- const props = defineProps({
9
- format: {
10
- type: String,
11
- default: 'Human'
12
- },
13
- start: {
14
- type: [Number, String],
15
- required: true
16
- },
17
- end: {
18
- type: [Number, String],
19
- required: true
20
- },
21
- })
8
+ export interface EpochRangeProps {
9
+ format?: string;
10
+ start: number | string;
11
+ end: number | string;
12
+ }
13
+
14
+ const props = withDefaults(defineProps<EpochRangeProps>(), {
15
+ format: 'Human'
16
+ });
22
17
 
23
- const suffix = {
18
+ const suffix: Record<string, string> = {
24
19
  1: 'st',
25
20
  2: 'nd',
26
21
  3: 'rd'
@@ -28,28 +28,24 @@
28
28
  </Modal>
29
29
  </template>
30
30
 
31
- <script setup>
31
+ <script setup lang="ts">
32
32
  import Modal from './Modal.vue'
33
33
  import Alert from './Alert.vue'
34
34
 
35
- defineProps({
36
- err: {
37
- type: Error,
38
- required: true
39
- },
40
- title: {
41
- type: String,
42
- default: 'Website Error'
43
- },
44
- trace: {
45
- type: Boolean,
46
- default: true
47
- }
48
- })
35
+ export interface ErrProps {
36
+ err: Error;
37
+ title?: string;
38
+ trace?: boolean;
39
+ }
40
+
41
+ withDefaults(defineProps<ErrProps>(), {
42
+ title: 'Website Error',
43
+ trace: true
44
+ });
49
45
 
50
- const emit = defineEmits([
51
- 'close'
52
- ])
46
+ const emit = defineEmits<{
47
+ (e: 'close'): void
48
+ }>()
53
49
 
54
50
  const close = () => {
55
51
  emit('close')
@@ -34,23 +34,21 @@
34
34
  </Modal>
35
35
  </template>
36
36
 
37
- <script setup>
37
+ <script setup lang="ts">
38
38
  import Modal from './Modal.vue'
39
39
 
40
- defineProps({
41
- label: {
42
- type: String,
43
- default: 'Help'
44
- },
45
- description: {
46
- type: String,
47
- required: true
48
- }
49
- })
40
+ export interface HelpProps {
41
+ label?: string;
42
+ description: string;
43
+ }
44
+
45
+ withDefaults(defineProps<HelpProps>(), {
46
+ label: 'Help'
47
+ });
50
48
 
51
- const emit = defineEmits([
52
- 'close'
53
- ])
49
+ const emit = defineEmits<{
50
+ (e: 'close'): void
51
+ }>()
54
52
 
55
53
  const close = () => {
56
54
  emit('close')
@@ -10,33 +10,29 @@
10
10
  "custom-hover": props.hover,
11
11
  }'
12
12
  class='rounded'
13
- @keyup.enter='icon.click()'
13
+ @keyup.enter='icon?.click()'
14
14
  >
15
15
  <slot />
16
16
  </div>
17
17
  </template>
18
18
 
19
- <script setup>
19
+ <script setup lang="ts">
20
20
  import { useId, useTemplateRef } from 'vue'
21
21
 
22
22
  const iconid = useId();
23
23
 
24
- const icon = useTemplateRef(iconid);
24
+ const icon = useTemplateRef<HTMLElement>(iconid);
25
25
 
26
- const props = defineProps({
27
- title: {
28
- type: String,
29
- required: true
30
- },
31
- hover: {
32
- type: Boolean,
33
- default: true
34
- },
35
- disabled: {
36
- type: Boolean,
37
- default: false
38
- }
39
- })
26
+ export interface IconButtonProps {
27
+ title: string;
28
+ hover?: boolean;
29
+ disabled?: boolean;
30
+ }
31
+
32
+ const props = withDefaults(defineProps<IconButtonProps>(), {
33
+ hover: true,
34
+ disabled: false
35
+ });
40
36
  </script>
41
37
 
42
38
  <style scoped>
@@ -63,12 +63,14 @@ import {
63
63
  IconAlertTriangle
64
64
  } from '@tabler/icons-vue';
65
65
 
66
- const props = withDefaults(defineProps<{
67
- severity?: string // info, danger, warning, success
68
- title: string
69
- description?: string
70
- dismissable?: boolean
71
- }>(), {
66
+ export interface InlineAlertProps {
67
+ severity?: 'info' | 'danger' | 'warning' | 'success';
68
+ title: string;
69
+ description?: string;
70
+ dismissable?: boolean;
71
+ }
72
+
73
+ const props = withDefaults(defineProps<InlineAlertProps>(), {
72
74
  severity: 'info',
73
75
  dismissable: false,
74
76
  });