@naptics/vue-collection 0.2.15 → 0.3.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 (170) hide show
  1. package/.github/workflows/build.yml +26 -0
  2. package/.github/workflows/deploy-demo.yml +46 -0
  3. package/.github/workflows/deploy-lib.yml +65 -0
  4. package/.gitlab-ci.yml +57 -0
  5. package/.nvmrc +1 -0
  6. package/.prettierrc +8 -0
  7. package/.vscode/extensions.json +10 -0
  8. package/.vscode/launch.json +23 -0
  9. package/.vscode/settings.json +13 -0
  10. package/babel.config.json +3 -0
  11. package/components/NAlert.d.ts +1 -44
  12. package/components/NBadge.d.ts +1 -133
  13. package/components/NBreadcrub.d.ts +2 -106
  14. package/components/NBreadcrub.js +1 -1
  15. package/components/NButton.d.ts +2 -118
  16. package/components/NCheckbox.d.ts +1 -32
  17. package/components/NCheckboxLabel.d.ts +1 -45
  18. package/components/NCheckboxLabel.js +1 -1
  19. package/components/NCrudModal.d.ts +7 -251
  20. package/components/NCrudModal.js +1 -1
  21. package/components/NDialog.d.ts +1 -110
  22. package/components/NDialog.js +1 -1
  23. package/components/NDropdown.d.ts +1 -69
  24. package/components/NDropdown.js +1 -1
  25. package/components/NDropzone.d.ts +1 -115
  26. package/components/NDropzone.js +1 -1
  27. package/components/NForm.d.ts +1 -23
  28. package/components/NFormModal.d.ts +7 -151
  29. package/components/NIconButton.d.ts +3 -159
  30. package/components/NIconButton.js +1 -1
  31. package/components/NIconCircle.d.ts +1 -87
  32. package/components/NInput.d.ts +1 -164
  33. package/components/NInput.js +1 -1
  34. package/components/NInputPhone.d.ts +2 -114
  35. package/components/NInputPhone.js +1 -1
  36. package/components/NInputSelect.d.ts +2 -187
  37. package/components/NInputSelect.js +1 -1
  38. package/components/NInputSuggestion.d.ts +2 -155
  39. package/components/NInputSuggestion.js +1 -1
  40. package/components/NLink.d.ts +1 -70
  41. package/components/NList.d.ts +1 -43
  42. package/components/NList.js +1 -1
  43. package/components/NLoadingIndicator.d.ts +1 -49
  44. package/components/NModal.d.ts +12 -250
  45. package/components/NModal.js +15 -9
  46. package/components/NPagination.d.ts +1 -63
  47. package/components/NSearchbar.d.ts +1 -56
  48. package/components/NSearchbarList.d.ts +3 -63
  49. package/components/NSearchbarList.js +1 -1
  50. package/components/NSelect.d.ts +2 -148
  51. package/components/NSelect.js +1 -1
  52. package/components/NSuggestionList.d.ts +3 -126
  53. package/components/NSuggestionList.js +5 -2
  54. package/components/NTable.d.ts +1 -85
  55. package/components/NTable.js +12 -6
  56. package/components/NTableAction.d.ts +2 -46
  57. package/components/NTableAction.js +1 -1
  58. package/components/NTextArea.d.ts +2 -181
  59. package/components/NTextArea.js +1 -1
  60. package/components/NTooltip.d.ts +1 -105
  61. package/components/NTooltip.js +1 -1
  62. package/components/NValInput.d.ts +7 -182
  63. package/components/NValInput.js +1 -1
  64. package/env.d.ts +15 -0
  65. package/eslint.config.cjs +29 -0
  66. package/index.html +13 -0
  67. package/package.json +21 -19
  68. package/postcss.config.js +6 -0
  69. package/public/favicon.ico +0 -0
  70. package/scripts/build-lib.sh +52 -0
  71. package/scripts/sync-node-types.js +70 -0
  72. package/src/demo/App.css +9 -0
  73. package/src/demo/App.tsx +5 -0
  74. package/src/demo/components/ColorGrid.tsx +26 -0
  75. package/src/demo/components/ComponentGrid.tsx +26 -0
  76. package/src/demo/components/ComponentSection.tsx +30 -0
  77. package/src/demo/components/VariantSection.tsx +18 -0
  78. package/src/demo/i18n/de.ts +7 -0
  79. package/src/demo/i18n/en.ts +7 -0
  80. package/src/demo/i18n/index.ts +24 -0
  81. package/src/demo/main.ts +13 -0
  82. package/src/demo/router/index.ts +21 -0
  83. package/src/demo/views/HomeView.tsx +94 -0
  84. package/src/demo/views/NavigationView.tsx +43 -0
  85. package/src/demo/views/presentation/AlertView.tsx +40 -0
  86. package/src/demo/views/presentation/BadgeView.tsx +61 -0
  87. package/src/demo/views/presentation/BreadcrumbView.tsx +52 -0
  88. package/src/demo/views/presentation/ButtonView.tsx +49 -0
  89. package/src/demo/views/presentation/CheckboxView.tsx +59 -0
  90. package/src/demo/views/presentation/DropdownView.tsx +59 -0
  91. package/src/demo/views/presentation/DropzoneView.tsx +39 -0
  92. package/src/demo/views/presentation/IconButtonView.tsx +47 -0
  93. package/src/demo/views/presentation/IconCircleView.tsx +38 -0
  94. package/src/demo/views/presentation/InputView.tsx +179 -0
  95. package/src/demo/views/presentation/LinkView.tsx +50 -0
  96. package/src/demo/views/presentation/ListView.tsx +29 -0
  97. package/src/demo/views/presentation/LoadingIndicatorView.tsx +38 -0
  98. package/src/demo/views/presentation/ModalView.tsx +210 -0
  99. package/src/demo/views/presentation/PaginationView.tsx +25 -0
  100. package/src/demo/views/presentation/SearchbarView.tsx +80 -0
  101. package/src/demo/views/presentation/TableView.tsx +146 -0
  102. package/src/demo/views/presentation/TooltipView.tsx +86 -0
  103. package/src/lib/components/NAlert.tsx +85 -0
  104. package/src/lib/components/NBadge.tsx +75 -0
  105. package/src/lib/components/NBreadcrub.tsx +97 -0
  106. package/src/lib/components/NButton.tsx +80 -0
  107. package/src/lib/components/NCheckbox.tsx +55 -0
  108. package/src/lib/components/NCheckboxLabel.tsx +51 -0
  109. package/src/lib/components/NCrudModal.tsx +133 -0
  110. package/src/lib/components/NDialog.tsx +182 -0
  111. package/src/lib/components/NDropdown.tsx +167 -0
  112. package/src/lib/components/NDropzone.tsx +265 -0
  113. package/src/lib/components/NForm.tsx +32 -0
  114. package/src/lib/components/NFormModal.tsx +66 -0
  115. package/src/lib/components/NIconButton.tsx +92 -0
  116. package/src/lib/components/NIconCircle.tsx +78 -0
  117. package/src/lib/components/NInput.css +11 -0
  118. package/src/lib/components/NInput.tsx +139 -0
  119. package/src/lib/components/NInputPhone.tsx +53 -0
  120. package/src/lib/components/NInputSelect.tsx +126 -0
  121. package/src/lib/components/NInputSuggestion.tsx +80 -0
  122. package/src/lib/components/NLink.tsx +68 -0
  123. package/src/lib/components/NList.tsx +67 -0
  124. package/src/lib/components/NLoadingIndicator.css +46 -0
  125. package/src/lib/components/NLoadingIndicator.tsx +63 -0
  126. package/src/lib/components/NModal.tsx +243 -0
  127. package/src/lib/components/NPagination.css +15 -0
  128. package/src/lib/components/NPagination.tsx +131 -0
  129. package/src/lib/components/NSearchbar.tsx +78 -0
  130. package/src/lib/components/NSearchbarList.tsx +47 -0
  131. package/src/lib/components/NSelect.tsx +128 -0
  132. package/src/lib/components/NSuggestionList.tsx +216 -0
  133. package/src/lib/components/NTable.css +3 -0
  134. package/src/lib/components/NTable.tsx +247 -0
  135. package/src/lib/components/NTableAction.tsx +49 -0
  136. package/src/lib/components/NTextArea.tsx +159 -0
  137. package/src/lib/components/NTooltip.css +37 -0
  138. package/src/lib/components/NTooltip.tsx +250 -0
  139. package/src/lib/components/NValInput.tsx +163 -0
  140. package/src/lib/components/ValidatedForm.ts +71 -0
  141. package/src/lib/components/__tests__/NButton.spec.tsx +26 -0
  142. package/src/lib/components/__tests__/NCheckbox.spec.tsx +39 -0
  143. package/src/lib/i18n/de/vue-collection.json +58 -0
  144. package/src/lib/i18n/en/vue-collection.json +58 -0
  145. package/src/lib/i18n/index.ts +54 -0
  146. package/src/lib/index.ts +2 -0
  147. package/src/lib/jsx.d.ts +13 -0
  148. package/src/lib/utils/__tests__/identifiable.spec.ts +72 -0
  149. package/src/lib/utils/__tests__/validation.spec.ts +92 -0
  150. package/src/lib/utils/breakpoints.ts +47 -0
  151. package/src/lib/utils/component.tsx +131 -0
  152. package/src/lib/utils/deferred.ts +28 -0
  153. package/src/lib/utils/identifiable.ts +87 -0
  154. package/src/lib/utils/stringMaxLength.ts +25 -0
  155. package/src/lib/utils/tailwind.ts +41 -0
  156. package/src/lib/utils/utils.ts +90 -0
  157. package/src/lib/utils/vModel.ts +260 -0
  158. package/src/lib/utils/validation.ts +189 -0
  159. package/src/lib/utils/vue.ts +25 -0
  160. package/tailwind.config.js +38 -0
  161. package/tsconfig.config.json +9 -0
  162. package/tsconfig.demo.json +19 -0
  163. package/tsconfig.json +16 -0
  164. package/tsconfig.lib.json +18 -0
  165. package/tsconfig.vitest.json +8 -0
  166. package/utils/breakpoints.d.ts +1 -1
  167. package/utils/component.d.ts +3 -7
  168. package/utils/component.js +5 -2
  169. package/utils/identifiable.js +5 -1
  170. package/vite.config.ts +28 -0
@@ -0,0 +1,133 @@
1
+ import { trsl } from '../i18n'
2
+ import { createComponentWithSlots } from '../utils/component'
3
+ import { ref, type PropType } from 'vue'
4
+ import NButton from './NButton'
5
+ import type { DialogVariant, NDialogExposed } from './NDialog'
6
+ import NDialog from './NDialog'
7
+ import NFormModal, { nFormModalProps } from './NFormModal'
8
+
9
+ export const nCrudModalProps = {
10
+ ...nFormModalProps,
11
+ /**
12
+ * The text of the remove-button.
13
+ */
14
+ removeText: {
15
+ type: String,
16
+ default: trsl('vue-collection.action.remove'),
17
+ },
18
+ /**
19
+ * The color of the remove-button.
20
+ */
21
+ removeColor: {
22
+ type: String,
23
+ default: 'red',
24
+ },
25
+ /**
26
+ * If set to `true` the remove-button is disabled.
27
+ */
28
+ removeDisabled: Boolean,
29
+ /**
30
+ * If set to `true` the ok-button is hidden.
31
+ */
32
+ hideRemove: Boolean,
33
+ /**
34
+ * If set to `true` the ok-button is disabled.
35
+ */
36
+ okDisabled: Boolean,
37
+ /**
38
+ * The title of the dialog which appears when clicking on the remove-button.
39
+ */
40
+ removeDialogTitle: String,
41
+ /**
42
+ * The text of the dialog which appears when clicking on the remove-button.
43
+ */
44
+ removeDialogText: String,
45
+ /**
46
+ * The variant of the dialog which appears when clicking on the remove-button. Default is `remove`.
47
+ */
48
+ removeDialogVariant: {
49
+ type: String as PropType<DialogVariant>,
50
+ default: 'remove',
51
+ },
52
+ /**
53
+ * The text of the dialog's ok-button. Is already set by the `removeDialogVariant` but can be overridden.
54
+ */
55
+ removeDialogOkText: String,
56
+ /**
57
+ * If set to `true` the modal will close itself when `onRemove` is called.
58
+ */
59
+ closeOnRemove: {
60
+ type: Boolean,
61
+ default: true,
62
+ },
63
+ /**
64
+ * This is called, when the remove-button has been clicked and the dialog has been accepted.
65
+ */
66
+ onRemove: Function as PropType<() => void>,
67
+ } as const
68
+
69
+ /**
70
+ * The `NCrudModal` is a {@link NFormModal} which has some convenience features for a CRUD-scenario.
71
+ * It has an integrated remove-button with a user-dialog to remove the editing element.
72
+ * When the dialog is accepted `onRemove` is called.
73
+ */
74
+ const Component = createComponentWithSlots(
75
+ 'NCrudModal',
76
+ nCrudModalProps,
77
+ ['modal', 'footer', 'header'],
78
+ (props, { slots }) => {
79
+ const removeDialog = ref<NDialogExposed>()
80
+
81
+ const remove = () => {
82
+ removeDialog.value?.show().then(result => {
83
+ if (result) {
84
+ props.onRemove?.()
85
+ if (props.closeOnRemove) props.onUpdateValue?.(false)
86
+ }
87
+ })
88
+ }
89
+
90
+ return () => (
91
+ <NFormModal
92
+ {...props}
93
+ footer={
94
+ props.footer ||
95
+ (({ ok, cancel }) => (
96
+ <div class="flex justify-between">
97
+ <div>
98
+ {!props.hideRemove && (
99
+ <NButton color={props.removeColor} onClick={remove} disabled={props.removeDisabled}>
100
+ {props.removeText}
101
+ </NButton>
102
+ )}
103
+ </div>
104
+ <div class="flex justify-end space-x-2">
105
+ {!props.hideCancel && (
106
+ <NButton color={props.cancelColor} onClick={cancel}>
107
+ {props.cancelText}
108
+ </NButton>
109
+ )}
110
+ {!props.hideOk && (
111
+ <NButton color={props.okColor} onClick={ok} disabled={props.okDisabled}>
112
+ {props.okText}
113
+ </NButton>
114
+ )}
115
+ </div>
116
+ </div>
117
+ ))
118
+ }
119
+ >
120
+ {slots.default?.()}
121
+ <NDialog
122
+ ref={removeDialog}
123
+ variant={props.removeDialogVariant}
124
+ title={props.removeDialogTitle}
125
+ text={props.removeDialogText}
126
+ okText={props.removeDialogOkText}
127
+ />
128
+ </NFormModal>
129
+ )
130
+ }
131
+ )
132
+
133
+ export { Component as NCrudModal, Component as default }
@@ -0,0 +1,182 @@
1
+ import { deferred, type DeferredPromise } from '../utils/deferred'
2
+ import { createComponent, extractProps } from '../utils/component'
3
+ import { CheckIcon, ExclamationTriangleIcon, LightBulbIcon, TrashIcon } from '@heroicons/vue/24/outline'
4
+ import { computed, ref, type PropType } from 'vue'
5
+ import NIconCircle from './NIconCircle'
6
+ import NModal from './NModal'
7
+ import { DialogTitle } from '@headlessui/vue'
8
+ import type { HeroIcon } from '../utils/tailwind'
9
+ import { trsl } from '../i18n'
10
+ import { vModelForRef } from '../utils/vModel'
11
+
12
+ export type DialogVariant = 'success' | 'info' | 'warning' | 'danger' | 'remove'
13
+
14
+ export const nDialogProps = {
15
+ /**
16
+ * The title of the dialog.
17
+ */
18
+ title: String,
19
+ /**
20
+ * The text of the dialog.
21
+ */
22
+ text: String,
23
+ /**
24
+ * The variant of the dialog.
25
+ * This determines the default icon and its color
26
+ * as well as the default text and color of the ok-button.
27
+ */
28
+ variant: {
29
+ type: String as PropType<DialogVariant>,
30
+ default: 'warning',
31
+ },
32
+ /**
33
+ * The icon of the alert. This overrides the `icon` of the `variant`.
34
+ */
35
+ icon: Function as PropType<HeroIcon>,
36
+ /**
37
+ * The color of the alert's icon. This overrides the `iconColor` of the `variant`.
38
+ */
39
+ iconColor: String,
40
+ /**
41
+ * The text of the ok-button. This overrides the `okText` of the `variant`.
42
+ */
43
+ okText: String,
44
+ /**
45
+ * The color of the ok-button. This overrides the `okColor` of the `variant`.
46
+ */
47
+ okColor: String,
48
+ /**
49
+ * The text of the cancel-button.
50
+ */
51
+ cancelText: {
52
+ type: String,
53
+ default: trsl('vue-collection.action.cancel'),
54
+ },
55
+ /**
56
+ * The color of the cancel-button.
57
+ */
58
+ cancelColor: {
59
+ type: String,
60
+ default: 'default',
61
+ },
62
+ /**
63
+ * If set to `true` the cancel-button is hidden.
64
+ */
65
+ hideCancel: Boolean,
66
+ }
67
+
68
+ export type NDialogExposed = {
69
+ /**
70
+ * Shows the alert and returns a promise.
71
+ * When the user interaction occurs the promise is resolved.
72
+ * It is resolved to `true` if the okButton was clicked, `false` if the dialog was cancelled.
73
+ */
74
+ show(): Promise<boolean>
75
+ }
76
+
77
+ /**
78
+ * A `NDialog` is an element to interact directly with the user.
79
+ * It can be controlled via a ref to prompt the user and to receive their answer.
80
+ * @example
81
+ * const dialogRef = ref<NDialogExposed>()
82
+ * ...
83
+ * const onShowDialog = () => {
84
+ * dialofRef.value?.show().then(result => {
85
+ * if (result) // dialog accepted
86
+ * else // dialog cancelled
87
+ * })
88
+ * }
89
+ * ...
90
+ * <NDialog ref={dialogRef} />
91
+ */
92
+ const Component = createComponent('NDialog', nDialogProps, (props, context) => {
93
+ const showDialog = ref(false)
94
+
95
+ let deferredPromise: DeferredPromise<boolean> | null = null
96
+ const show = (): Promise<boolean> => {
97
+ if (deferredPromise != null) {
98
+ deferredPromise.reject('show() was called on the open dialog.')
99
+ deferredPromise = null
100
+ }
101
+ showDialog.value = true
102
+ deferredPromise = deferred<boolean>()
103
+ return deferredPromise.promise
104
+ }
105
+
106
+ context.expose({ show })
107
+
108
+ const resolveWith = (result: boolean) => {
109
+ deferredPromise?.resolve(result)
110
+ deferredPromise = null
111
+ }
112
+
113
+ const ok = () => resolveWith(true)
114
+ const cancel = () => resolveWith(false)
115
+
116
+ const defaults = computed(() => VARIANT_DEFAULTS[props.variant])
117
+
118
+ return () => (
119
+ <NModal
120
+ {...vModelForRef(showDialog)}
121
+ {...extractProps(props, 'cancelColor', 'cancelText', 'hideCancel')}
122
+ onOk={ok}
123
+ onCancel={cancel}
124
+ okColor={props.okColor || defaults.value.okColor}
125
+ okText={props.okText || defaults.value.okText}
126
+ hideX
127
+ hideHeader
128
+ >
129
+ <div class="flex space-x-4 py-2">
130
+ <div class="flex-grow-0">
131
+ <NIconCircle
132
+ icon={props.icon || defaults.value.icon}
133
+ iconSize={6}
134
+ color={props.iconColor || defaults.value.iconColor}
135
+ />
136
+ </div>
137
+
138
+ <div class="flex-grow">
139
+ <DialogTitle as="h4" class="font-medium text-lg text-default-700 mb-1">
140
+ {props.title}
141
+ </DialogTitle>
142
+ {context.slots.default?.() || <p class="text-sm text-default-500">{props.text}</p>}
143
+ </div>
144
+ </div>
145
+ </NModal>
146
+ )
147
+ })
148
+
149
+ const VARIANT_DEFAULTS = {
150
+ success: {
151
+ icon: CheckIcon,
152
+ iconColor: 'green',
153
+ okText: trsl('vue-collection.action.all-right'),
154
+ okColor: 'green',
155
+ },
156
+ info: {
157
+ icon: LightBulbIcon,
158
+ iconColor: 'blue',
159
+ okText: trsl('vue-collection.action.all-right'),
160
+ okColor: 'blue',
161
+ },
162
+ warning: {
163
+ icon: ExclamationTriangleIcon,
164
+ iconColor: 'yellow',
165
+ okText: trsl('vue-collection.action.proceed'),
166
+ okColor: 'yellow',
167
+ },
168
+ danger: {
169
+ icon: ExclamationTriangleIcon,
170
+ iconColor: 'red',
171
+ okText: trsl('vue-collection.action.proceed'),
172
+ okColor: 'red',
173
+ },
174
+ remove: {
175
+ icon: TrashIcon,
176
+ iconColor: 'red',
177
+ okText: trsl('vue-collection.action.remove'),
178
+ okColor: 'red',
179
+ },
180
+ }
181
+
182
+ export { Component as NDialog, Component as default }
@@ -0,0 +1,167 @@
1
+ import { createComponentWithSlots } from '../utils/component'
2
+ import { computed, Transition, type PropType } from 'vue'
3
+ import { RouterLink, type RouteLocationRaw } from 'vue-router'
4
+ import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
5
+ import { ChevronDownIcon } from '@heroicons/vue/24/solid'
6
+ import type { HeroIcon } from '../utils/tailwind'
7
+
8
+ export const nDropdownProps = {
9
+ /**
10
+ * The title of the dropdown-button.
11
+ */
12
+ title: String,
13
+ /**
14
+ * The items of the dropdown.
15
+ * The second dimension of the array is used
16
+ * to create groups of items, which are visually seperated.
17
+ */
18
+ items: {
19
+ type: Array as PropType<DropdownItem[] | DropdownItem[][]>,
20
+ default: () => [],
21
+ },
22
+ /**
23
+ * If set to `true` the panel is right-aligned to the button.
24
+ */
25
+ right: Boolean,
26
+ /**
27
+ * If set to `true` the dropdown-button is disabled and no interaction is possible.
28
+ */
29
+ disabled: Boolean,
30
+ /**
31
+ * Adds the classes to the Button of the dropdown.
32
+ */
33
+ buttonClass: String,
34
+ /**
35
+ * A slot to replace the button of the dropdown.
36
+ * The passed parameter is the HeadlessUI `MenuButton` which should be
37
+ * used to create the button for the Dropdown to work properly.
38
+ */
39
+ button: Function as PropType<(button: typeof MenuButton) => JSX.Element>,
40
+ } as const
41
+
42
+ export type DropdownItem = {
43
+ /**
44
+ * The label of the dropdown-item.
45
+ */
46
+ label: string
47
+ /**
48
+ * The icon of the dropdown-item. Is displayed to the left of the text.
49
+ */
50
+ icon?: HeroIcon
51
+ /**
52
+ * The route of the dropdown-item. If this is set, the dropdown-item is a {@link RouterLink}.
53
+ */
54
+ route?: RouteLocationRaw
55
+ /**
56
+ * If set to `true` the dropdown-item is disabled and no interaction is possible.
57
+ * The other dropdown-items can still be clicked.
58
+ */
59
+ disabled?: boolean
60
+ /**
61
+ * This is called when the dropdown-item is clicked.
62
+ * It is only called when the `route` option is not set on the item.
63
+ */
64
+ onClick?: () => void
65
+ }
66
+
67
+ /**
68
+ * The `NDropdown` consists of a button and a panel with multiple actions.
69
+ * It is useful to group multiple actions together in one place.
70
+ */
71
+ const Component = createComponentWithSlots('NDropdown', nDropdownProps, ['button'], (props, { slots }) => {
72
+ const items = computed<DropdownItem[][]>(() => {
73
+ if (props.items.length == 0) return []
74
+ if (Array.isArray(props.items[0])) return props.items as DropdownItem[][]
75
+ else return [props.items] as DropdownItem[][]
76
+ })
77
+
78
+ const itemWithIcon = (item: DropdownItem) => (
79
+ <div class="flex space-x-3 items-center">
80
+ {item.icon && <item.icon class={['h-5 w-5', item.disabled ? 'text-default-300' : 'text-default-400']} />}
81
+ <span>{item.label}</span>
82
+ </div>
83
+ )
84
+
85
+ return () => (
86
+ <Menu as="div" class={`relative inline-block text-left`}>
87
+ <div class="flex">
88
+ {props.button?.(MenuButton) || (
89
+ <MenuButton
90
+ disabled={props.disabled}
91
+ class={[
92
+ 'shadow w-full flex justify-between items-center text-default-700 rounded-md border bg-white border-default-300 px-4 py-2 text-sm font-medium focus:outline-none focus:ring-offset-2 focus-visible:ring-2 focus-visible:ring-primary-500',
93
+ props.disabled ? 'text-opacity-20 cursor-default' : 'hover:bg-default-100',
94
+ props.buttonClass,
95
+ ]}
96
+ >
97
+ <span>{props.title}</span>
98
+ <ChevronDownIcon class="-mr-1 ml-2 h-5 w-5 flex-shrink-0" aria-hidden="true" />
99
+ </MenuButton>
100
+ )}
101
+ </div>
102
+
103
+ <Transition
104
+ enterActiveClass="transition ease-out duration-100"
105
+ enterFromClass="transform opacity-0 scale-95"
106
+ enterToClass="transform opacity-100 scale-100"
107
+ leaveActiveClass="transition ease-in duration-75"
108
+ leaveFromClass="transform opacity-100 scale-100"
109
+ leaveToClass="transform opacity-0 scale-95"
110
+ >
111
+ <MenuItems
112
+ class={[
113
+ 'z-10 absolute w-56 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none',
114
+ props.right ? 'origin-top-right right-0' : 'origin-top-left left-0',
115
+ ]}
116
+ >
117
+ {slots.default?.() || (
118
+ <div class="divide-y divide-default-200">
119
+ {items.value.map((group, index) => (
120
+ <div key={`group-${index}`} class="py-1">
121
+ {group.map((item, index) => (
122
+ <MenuItem key={`item-${index}`} disabled={item.disabled}>
123
+ {({ active }: { active: boolean }) =>
124
+ item.disabled ? (
125
+ <div class="block px-4 py-2 text-sm text-default-300">
126
+ {itemWithIcon(item)}
127
+ </div>
128
+ ) : item.route ? (
129
+ <RouterLink
130
+ to={item.route}
131
+ class={[
132
+ 'block px-4 py-2 text-sm',
133
+ active
134
+ ? 'bg-default-100 text-default-900'
135
+ : 'text-default-700',
136
+ ]}
137
+ >
138
+ {itemWithIcon(item)}
139
+ </RouterLink>
140
+ ) : (
141
+ <button
142
+ type="button"
143
+ onClick={item.onClick}
144
+ class={[
145
+ 'w-full text-left px-4 py-2 text-sm',
146
+ active
147
+ ? 'bg-default-100 text-default-900'
148
+ : 'text-default-700',
149
+ ]}
150
+ >
151
+ {itemWithIcon(item)}
152
+ </button>
153
+ )
154
+ }
155
+ </MenuItem>
156
+ ))}
157
+ </div>
158
+ ))}
159
+ </div>
160
+ )}
161
+ </MenuItems>
162
+ </Transition>
163
+ </Menu>
164
+ )
165
+ })
166
+
167
+ export { Component as NDropdown, Component as default }