@sbc-connect/nuxt-base 0.1.23 → 0.1.24
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 +6 -0
- package/app/app.config.ts +0 -3
- package/app/components/Connect/ButtonControl/Buttons.vue +27 -0
- package/app/components/Connect/ButtonControl/Index.vue +66 -0
- package/app/components/Connect/ButtonControl/Wrapper.vue +18 -0
- package/app/composables/useConnectButtonControl.ts +146 -0
- package/app/interfaces/connect-button-control.ts +22 -0
- package/modules/base-assets/runtime/assets/connect-base-tw.css +0 -11
- package/nuxt.config.ts +3 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @sbc-connect/nuxt-base
|
|
2
2
|
|
|
3
|
+
## 0.1.24
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#80](https://github.com/bcgov/connect-nuxt/pull/80) [`0615542`](https://github.com/bcgov/connect-nuxt/commit/06155422d0a8d61ee862bb3483330610b4a9434d) Thanks [@deetz99](https://github.com/deetz99)! - feat: Move button control to base and handle loading state internally
|
|
8
|
+
|
|
3
9
|
## 0.1.23
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/app/app.config.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
defineProps<{ buttons: ConnectButton[], position: 'left' | 'right' }>()
|
|
3
|
+
|
|
4
|
+
// remove alertText and removeAlertSpacing from being added to button html attrs
|
|
5
|
+
const removeButtonAttrs = (button: ConnectButton) => {
|
|
6
|
+
const newButton = { ...button }
|
|
7
|
+
delete newButton['alertText']
|
|
8
|
+
delete newButton['removeAlertSpacing']
|
|
9
|
+
return newButton
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<div
|
|
15
|
+
v-for="(button, i) in buttons"
|
|
16
|
+
:key="`${position}-button-${i}`"
|
|
17
|
+
data-testid="button-wrapper"
|
|
18
|
+
>
|
|
19
|
+
<UButton
|
|
20
|
+
class="max-w-fit px-7 py-3 mb-1"
|
|
21
|
+
v-bind="removeButtonAttrs(button)"
|
|
22
|
+
/>
|
|
23
|
+
<p :class="['text-center', !button.removeAlertSpacing ? 'h-[1.25rem]' : '']">
|
|
24
|
+
<span v-if="button.alertText" class="text-error">{{ button.alertText }}</span>
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const {
|
|
3
|
+
stateKey = 'default-button-control'
|
|
4
|
+
} = defineProps<{
|
|
5
|
+
stateKey?: string
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
const { buttonControl: meta } = useConnectButtonControl(stateKey)
|
|
9
|
+
const buttonControl = computed(() => meta.value)
|
|
10
|
+
const leftGroup = computed(() => buttonControl.value?.leftGroup || [])
|
|
11
|
+
const rightGroup = computed(() => buttonControl.value?.rightGroup || [])
|
|
12
|
+
const leftAlertText = computed(() => buttonControl.value?.leftGroup.alertText || undefined)
|
|
13
|
+
const rightAlertText = computed(() => buttonControl.value?.rightGroup.alertText || undefined)
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<div
|
|
18
|
+
class="@container"
|
|
19
|
+
data-testid="connect-button-control"
|
|
20
|
+
>
|
|
21
|
+
<div class="grid grid-cols-1 gap-4 @3xl:grid-cols-2">
|
|
22
|
+
<div>
|
|
23
|
+
<div
|
|
24
|
+
class="flex justify-center @3xl:justify-start"
|
|
25
|
+
data-testid="left-buttons"
|
|
26
|
+
>
|
|
27
|
+
<div
|
|
28
|
+
class="relative flex flex-col flex-wrap gap-4 justify-center"
|
|
29
|
+
:class="leftGroup.stacked ? '' : 'flex-row'"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
v-if="leftAlertText"
|
|
33
|
+
class="absolute flex flex-wrap justify-start bottom-1/3 right-[-13rem] w-[12rem]"
|
|
34
|
+
>
|
|
35
|
+
<p class="text-error" role="alert">
|
|
36
|
+
{{ leftAlertText }}
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
<ConnectButtonControlButtons :buttons="leftGroup.buttons" position="left" />
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div>
|
|
44
|
+
<div
|
|
45
|
+
class="flex justify-center @3xl:justify-end"
|
|
46
|
+
data-testid="right-buttons"
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
class="relative flex flex-col flex-wrap gap-4 justify-center"
|
|
50
|
+
:class="rightGroup.stacked ? '' : 'flex-row'"
|
|
51
|
+
>
|
|
52
|
+
<div
|
|
53
|
+
v-if="rightAlertText"
|
|
54
|
+
class="absolute flex flex-wrap justify-end bottom-1/3 left-[-13rem] w-[12rem]"
|
|
55
|
+
>
|
|
56
|
+
<p class="text-error" role="alert">
|
|
57
|
+
{{ rightAlertText }}
|
|
58
|
+
</p>
|
|
59
|
+
</div>
|
|
60
|
+
<ConnectButtonControlButtons :buttons="rightGroup.buttons" position="right" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const {
|
|
3
|
+
stateKey = 'default-button-control'
|
|
4
|
+
} = defineProps<{
|
|
5
|
+
stateKey?: string
|
|
6
|
+
}>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<div
|
|
11
|
+
class="bg-shade-inverted pb-6 pt-10"
|
|
12
|
+
data-testid="connect-button-control-wrapper"
|
|
13
|
+
>
|
|
14
|
+
<div class="app-inner-container app-body">
|
|
15
|
+
<ConnectButtonControl :state-key="stateKey" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const defaultOptions: ConnectButtonControlOptions = {
|
|
2
|
+
handleLoading: true,
|
|
3
|
+
clearAlertTextOnClick: true
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const useConnectButtonControl = (
|
|
7
|
+
stateKey: string = 'default-button-control',
|
|
8
|
+
opts: Partial<ConnectButtonControlOptions> = {}
|
|
9
|
+
) => {
|
|
10
|
+
const options = {
|
|
11
|
+
...defaultOptions,
|
|
12
|
+
...opts
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const buttonControl = useState<ConnectButtonControl>(stateKey, () => ({
|
|
16
|
+
leftGroup: { buttons: [] },
|
|
17
|
+
rightGroup: { buttons: [] }
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
const forEachButton = (update: (button: ConnectButton, group: 'left' | 'right', index: number) => void) => {
|
|
21
|
+
buttonControl.value.leftGroup?.buttons?.forEach((btn, index) => update(btn, 'left', index))
|
|
22
|
+
buttonControl.value.rightGroup?.buttons?.forEach((btn, index) => update(btn, 'right', index))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const forEachGroup = (update: (group: ConnectButtonGroup) => void) => {
|
|
26
|
+
if (buttonControl.value.leftGroup) {
|
|
27
|
+
update(buttonControl.value.leftGroup)
|
|
28
|
+
}
|
|
29
|
+
if (buttonControl.value.rightGroup) {
|
|
30
|
+
update(buttonControl.value.rightGroup)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function setAlertText(text?: string, group?: 'left' | 'right', index?: number) {
|
|
35
|
+
forEachGroup(group => group.alertText = undefined)
|
|
36
|
+
forEachButton(btn => btn.alertText = undefined)
|
|
37
|
+
|
|
38
|
+
if (text && group !== undefined) {
|
|
39
|
+
await nextTick()
|
|
40
|
+
|
|
41
|
+
const buttonGroup = group === 'left' ? buttonControl.value.leftGroup : buttonControl.value.rightGroup
|
|
42
|
+
|
|
43
|
+
if (index !== undefined) {
|
|
44
|
+
const button = buttonGroup.buttons[index]
|
|
45
|
+
if (button) {
|
|
46
|
+
button.alertText = text
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
buttonGroup.alertText = text
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const handleClick = (
|
|
55
|
+
originalClick: ConnectButton['onClick'],
|
|
56
|
+
group: 'left' | 'right',
|
|
57
|
+
index: number
|
|
58
|
+
) => {
|
|
59
|
+
if (!originalClick || typeof originalClick !== 'function') {
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return async () => {
|
|
64
|
+
try {
|
|
65
|
+
if (options.clearAlertTextOnClick) {
|
|
66
|
+
await setAlertText(undefined)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (options.handleLoading) {
|
|
70
|
+
const clickedButton = buttonControl.value[group === 'left' ? 'leftGroup' : 'rightGroup']?.buttons[index]
|
|
71
|
+
if (!clickedButton) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
clickedButton.loading = true
|
|
76
|
+
forEachButton((button, btnGroup, btnIndex) => {
|
|
77
|
+
if (btnGroup !== group || btnIndex !== index) {
|
|
78
|
+
button.disabled = true
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
await (originalClick as () => Promise<void> | void)()
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (import.meta.env.DEV) {
|
|
86
|
+
console.error(`Error on button click. group: ${group} index: ${index} error: ${error}`)
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
if (options.handleLoading) {
|
|
90
|
+
forEachButton((button) => {
|
|
91
|
+
button.loading = false
|
|
92
|
+
button.disabled = false
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function setButtonControl(config: ConnectButtonControl) {
|
|
100
|
+
const updateGroup = (config: { buttons: ConnectButton[] }, group: 'left' | 'right') => {
|
|
101
|
+
if (!config || !config.buttons.length) {
|
|
102
|
+
return { ...config, buttons: [] }
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
...config,
|
|
106
|
+
buttons: config.buttons.map((button, index) => ({
|
|
107
|
+
...button,
|
|
108
|
+
onClick: handleClick(button.onClick, group, index)
|
|
109
|
+
}))
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
buttonControl.value = {
|
|
114
|
+
leftGroup: updateGroup(config.leftGroup, 'left'),
|
|
115
|
+
rightGroup: updateGroup(config.rightGroup, 'right')
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function handleButtonLoading(
|
|
120
|
+
loading: boolean,
|
|
121
|
+
group?: 'left' | 'right',
|
|
122
|
+
index?: number
|
|
123
|
+
) {
|
|
124
|
+
if (!loading) {
|
|
125
|
+
forEachButton((button) => {
|
|
126
|
+
button.loading = false
|
|
127
|
+
button.disabled = false
|
|
128
|
+
})
|
|
129
|
+
} else if (group !== undefined && index !== undefined) {
|
|
130
|
+
forEachButton((button, btnGroup, btnIndex) => {
|
|
131
|
+
if (btnGroup === group && btnIndex === index) {
|
|
132
|
+
button.loading = true
|
|
133
|
+
} else {
|
|
134
|
+
button.disabled = true
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
setButtonControl,
|
|
142
|
+
setAlertText,
|
|
143
|
+
handleButtonLoading,
|
|
144
|
+
buttonControl
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ButtonProps } from '@nuxt/ui'
|
|
2
|
+
|
|
3
|
+
export interface ConnectButton extends ButtonProps {
|
|
4
|
+
alertText?: string
|
|
5
|
+
removeAlertSpacing?: boolean
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ConnectButtonGroup {
|
|
9
|
+
alertText?: string
|
|
10
|
+
buttons: ConnectButton[]
|
|
11
|
+
stacked?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ConnectButtonControl {
|
|
15
|
+
leftGroup: ConnectButtonGroup
|
|
16
|
+
rightGroup: ConnectButtonGroup
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ConnectButtonControlOptions {
|
|
20
|
+
handleLoading: boolean
|
|
21
|
+
clearAlertTextOnClick: boolean
|
|
22
|
+
}
|
|
@@ -276,14 +276,3 @@ body {
|
|
|
276
276
|
@apply pointer-events-none absolute left-0 top-1 text-neutral text-xs font-medium px-2.5 transition-all duration-200 peer-focus:top-1 peer-focus:text-xs peer-placeholder-shown:text-sm peer-placeholder-shown:top-2.5 peer-focus:translate-none peer-focus:text-primary peer-aria-invalid:text-error;
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
|
-
|
|
280
|
-
/* TODO: maybe delete this */
|
|
281
|
-
/* Extra Utilities */
|
|
282
|
-
/* This should be working out-of-the-box from Nuxt UI but isnt for some reason */
|
|
283
|
-
/* https://ui.nuxt.com/getting-started/theme#neutral */
|
|
284
|
-
/* .text-highlighted {
|
|
285
|
-
color: var(--color-gray-900);
|
|
286
|
-
@variant dark {
|
|
287
|
-
color: var(--color-gray-900);
|
|
288
|
-
}
|
|
289
|
-
} */
|
package/nuxt.config.ts
CHANGED
|
@@ -120,10 +120,9 @@ export default defineNuxtConfig({
|
|
|
120
120
|
}
|
|
121
121
|
},
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// },
|
|
123
|
+
typescript: {
|
|
124
|
+
includeWorkspace: true // allow auto imports in tests
|
|
125
|
+
},
|
|
127
126
|
|
|
128
127
|
runtimeConfig: {
|
|
129
128
|
public: {
|