@icij/murmur-next 4.0.17 → 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/dist/lib/composables/chart.d.ts +3 -2
- package/dist/lib/composables/queryObserver.d.ts +6 -0
- package/dist/lib/datavisualisations/BarChart.vue.d.ts +3 -3
- package/dist/lib/datavisualisations/ColumnChart.vue.d.ts +4 -3
- package/dist/lib/datavisualisations/LineChart.vue.d.ts +1 -1
- package/dist/lib/datavisualisations/StackedBarChart.vue.d.ts +6 -8
- package/dist/lib/datavisualisations/StackedColumnChart.vue.d.ts +7 -6
- package/dist/lib/murmur.css +1 -1
- package/dist/lib/murmur.js +9191 -9158
- package/dist/lib/murmur.js.map +1 -1
- package/dist/lib/murmur.umd.cjs +36 -36
- package/dist/lib/murmur.umd.cjs.map +1 -1
- package/lib/components/ConfirmButton.vue +15 -4
- package/lib/components/SignUpForm.vue +11 -4
- package/lib/components/TinyPagination.vue +5 -1
- package/lib/composables/chart.ts +57 -38
- package/lib/composables/queryObserver.ts +66 -0
- package/lib/composables/sendEmail.ts +3 -1
- package/lib/datavisualisations/ColumnChart.vue +10 -4
- package/lib/datavisualisations/StackedBarChart.vue +63 -101
- package/lib/datavisualisations/StackedColumnChart.vue +56 -40
- package/lib/styles/variables.scss +2 -2
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
:model-value="showTooltip"
|
|
13
13
|
:placement="placement"
|
|
14
14
|
:target="uniqComponentId"
|
|
15
|
+
teleport-to="body"
|
|
15
16
|
manual
|
|
16
17
|
>
|
|
17
18
|
<div class="confirm-button__tooltip">
|
|
@@ -148,9 +149,19 @@ export default defineComponent({
|
|
|
148
149
|
emit('toggled', showTooltip.value)
|
|
149
150
|
}
|
|
150
151
|
|
|
152
|
+
function hideConfirmationTooltip(): void {
|
|
153
|
+
showTooltip.value = false
|
|
154
|
+
/**
|
|
155
|
+
* Emitted when the confirmation is toggled.
|
|
156
|
+
* @event toggled
|
|
157
|
+
* @param Boolean True if the button is shown.
|
|
158
|
+
*/
|
|
159
|
+
emit('toggled', false)
|
|
160
|
+
}
|
|
161
|
+
|
|
151
162
|
function cancel(): void {
|
|
152
|
-
|
|
153
|
-
props.cancelled()
|
|
163
|
+
hideConfirmationTooltip()
|
|
164
|
+
props.cancelled?.()
|
|
154
165
|
/**
|
|
155
166
|
* Emitted when the confirmation is cancelled.
|
|
156
167
|
* @event cancelled
|
|
@@ -159,8 +170,8 @@ export default defineComponent({
|
|
|
159
170
|
}
|
|
160
171
|
|
|
161
172
|
function confirm(): void {
|
|
162
|
-
|
|
163
|
-
props.confirmed()
|
|
173
|
+
hideConfirmationTooltip()
|
|
174
|
+
props.confirmed?.()
|
|
164
175
|
/**
|
|
165
176
|
* Emitted when the confirmation is confirmed.
|
|
166
177
|
* @event confirmed
|
|
@@ -141,11 +141,12 @@ export default defineComponent({
|
|
|
141
141
|
const variantColorClass = computed(() => {
|
|
142
142
|
return `btn-${props.variant}`
|
|
143
143
|
})
|
|
144
|
+
|
|
144
145
|
async function subscribe() {
|
|
145
146
|
resetMessages()
|
|
146
147
|
freeze()
|
|
147
148
|
// Send the data, catch the result no matter what and unfreeze the form
|
|
148
|
-
await send().then(done,
|
|
149
|
+
await send().then(done, error).finally(unfreeze)
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
function done({ result, msg }: any): void {
|
|
@@ -153,18 +154,24 @@ export default defineComponent({
|
|
|
153
154
|
email.value = ''
|
|
154
155
|
successMessage.value = msg
|
|
155
156
|
} else {
|
|
156
|
-
|
|
157
|
-
errorMessage.value =
|
|
158
|
-
last((msg || "Something's wrong").split('0 -')) ?? null
|
|
157
|
+
error({ msg })
|
|
159
158
|
}
|
|
160
159
|
}
|
|
160
|
+
|
|
161
|
+
// Mailchimp formats errors in list
|
|
162
|
+
function error({ msg }: any): void {
|
|
163
|
+
errorMessage.value = last((msg || "Something's wrong").split('0 -')) ?? null
|
|
164
|
+
}
|
|
165
|
+
|
|
161
166
|
function resetMessages() {
|
|
162
167
|
errorMessage.value = null
|
|
163
168
|
successMessage.value = null
|
|
164
169
|
}
|
|
170
|
+
|
|
165
171
|
function freeze() {
|
|
166
172
|
frozen.value = true
|
|
167
173
|
}
|
|
174
|
+
|
|
168
175
|
function unfreeze() {
|
|
169
176
|
frozen.value = false
|
|
170
177
|
}
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
<script lang="ts">
|
|
64
64
|
import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
|
|
65
|
-
import { defineComponent, PropType, ref, computed, onBeforeMount } from 'vue'
|
|
65
|
+
import { defineComponent, PropType, ref, computed, onBeforeMount, watch } from 'vue'
|
|
66
66
|
import { useI18n } from 'vue-i18n'
|
|
67
67
|
|
|
68
68
|
import { library, default as Fa } from './Fa'
|
|
@@ -187,6 +187,10 @@ export default defineComponent({
|
|
|
187
187
|
|
|
188
188
|
const currentPageInput = ref<number | string>(pageValue.value)
|
|
189
189
|
|
|
190
|
+
watch(() => props.modelValue, (value) => {
|
|
191
|
+
currentPageInput.value = value
|
|
192
|
+
})
|
|
193
|
+
|
|
190
194
|
function applyPageForm(): void {
|
|
191
195
|
if (!isNaN(currentPageInput.value as number)) {
|
|
192
196
|
emit('update:modelValue', +currentPageInput.value)
|
package/lib/composables/chart.ts
CHANGED
|
@@ -4,14 +4,15 @@ import isObject from 'lodash/isObject'
|
|
|
4
4
|
import isString from 'lodash/isString'
|
|
5
5
|
import max from 'lodash/max'
|
|
6
6
|
import some from 'lodash/some'
|
|
7
|
-
import { ComponentPublicInstance, computed,
|
|
7
|
+
import { ComponentPublicInstance, computed, toRef, toValue, ref, watch, onMounted, nextTick } from 'vue'
|
|
8
8
|
import { isUrl } from '@/utils/strings'
|
|
9
9
|
import { Ref, SetupContext } from '@vue/runtime-core'
|
|
10
10
|
import useResizeObserver from '@/composables/resizeObserver'
|
|
11
|
-
import { watchEffect } from 'vue'
|
|
12
11
|
|
|
13
12
|
type ChartContext<T extends string[]> = SetupContext<[...T, ...string[]]>
|
|
13
|
+
|
|
14
14
|
type ChartEmit = Pick<ChartContext<['resized', 'loaded']>, 'emit'>
|
|
15
|
+
|
|
15
16
|
type ChartProps = {
|
|
16
17
|
chartHeightRatio: { type: NumberConstructor }
|
|
17
18
|
data: {
|
|
@@ -28,13 +29,13 @@ type ChartProps = {
|
|
|
28
29
|
socialModeRatio: { default: number; type: NumberConstructor }
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
export function getChartProps(props: any):
|
|
32
|
+
export function getChartProps(props: any): any {
|
|
32
33
|
return {
|
|
33
|
-
chartHeightRatio: props
|
|
34
|
-
data: props
|
|
35
|
-
dataUrlType: props
|
|
36
|
-
socialMode: props
|
|
37
|
-
socialModeRatio: props
|
|
34
|
+
chartHeightRatio: toRef(props, 'chartHeightRatio'),
|
|
35
|
+
data: toRef(props, 'data'),
|
|
36
|
+
dataUrlType: toRef(props, 'dataUrlType'),
|
|
37
|
+
socialMode: toRef(props, 'socialMode'),
|
|
38
|
+
socialModeRatio: toRef(props, 'socialModeRatio')
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -76,10 +77,13 @@ export const chartProps = (): ChartProps => ({
|
|
|
76
77
|
default: 5 / 4
|
|
77
78
|
}
|
|
78
79
|
})
|
|
80
|
+
|
|
79
81
|
export const chartEmits = ['resized', 'loaded']
|
|
82
|
+
|
|
80
83
|
type Chart = {
|
|
81
84
|
dataHasHighlights: any
|
|
82
85
|
loadedData: any
|
|
86
|
+
mounted: Ref<boolean>,
|
|
83
87
|
xAxisYearFormat: (year: number | string) => number | string
|
|
84
88
|
elementsMaxBBox: ({
|
|
85
89
|
selector,
|
|
@@ -93,42 +97,51 @@ type Chart = {
|
|
|
93
97
|
d3Formatter: any
|
|
94
98
|
baseHeightRatio: any
|
|
95
99
|
}
|
|
100
|
+
|
|
96
101
|
export function useChart(
|
|
97
102
|
resizableRef: Ref<ComponentPublicInstance<HTMLElement> | null>,
|
|
98
|
-
props:
|
|
103
|
+
props: any,
|
|
99
104
|
{ emit }: ChartEmit,
|
|
100
105
|
isLoaded: Ref<boolean>,
|
|
101
106
|
onResized?: ()=>void,
|
|
102
107
|
afterLoaded?: () => Promise<any>
|
|
103
108
|
): Chart {
|
|
109
|
+
|
|
104
110
|
const { resizeRef, resizeState } = useResizeObserver(resizableRef)
|
|
105
111
|
const loadedData = ref<unknown|unknown[]>([])
|
|
112
|
+
const mounted = ref<boolean>(false)
|
|
113
|
+
const dataRef = toRef(props.data)
|
|
114
|
+
const dataUrlTypeRef = toRef(props.dataUrlType)
|
|
115
|
+
|
|
116
|
+
onMounted(() => {
|
|
117
|
+
nextTick(() => {
|
|
118
|
+
mounted.value = true
|
|
119
|
+
})
|
|
120
|
+
})
|
|
106
121
|
|
|
107
|
-
|
|
122
|
+
watch([dataRef, dataUrlTypeRef], async () => {
|
|
108
123
|
await document.fonts?.ready
|
|
124
|
+
|
|
125
|
+
const data = toValue(dataRef)
|
|
126
|
+
const dataUrlType = toValue(dataUrlTypeRef)
|
|
109
127
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
onResized()
|
|
128
|
-
emit('resized')
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
})
|
|
128
|
+
if (isString(data)) {
|
|
129
|
+
// @ts-expect-error introspection in typescript is tricky
|
|
130
|
+
loadedData.value = await d3[dataUrlType](data)
|
|
131
|
+
} else {
|
|
132
|
+
loadedData.value = data as unknown as []
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await afterLoaded?.()
|
|
136
|
+
isLoaded.value = true
|
|
137
|
+
emit('loaded')
|
|
138
|
+
|
|
139
|
+
if (onResized) {
|
|
140
|
+
onResized()
|
|
141
|
+
emit('resized')
|
|
142
|
+
}
|
|
143
|
+
}, { immediate: true })
|
|
144
|
+
|
|
132
145
|
function elementsMaxBBox({
|
|
133
146
|
selector = 'text',
|
|
134
147
|
defaultWidth = null,
|
|
@@ -160,9 +173,11 @@ export function useChart(
|
|
|
160
173
|
// previously using narrowWidth but it is automatically updated through resizeObserver state reactivity
|
|
161
174
|
return resizeState.narrowWidth ? '’' + String(year).slice(2, 4) : year
|
|
162
175
|
}
|
|
176
|
+
|
|
163
177
|
function highlighted(datum: { highlight: boolean }) {
|
|
164
178
|
return datum.highlight
|
|
165
179
|
}
|
|
180
|
+
|
|
166
181
|
function d3Formatter(value: any, formatter: any) {
|
|
167
182
|
if (isFunction(formatter)) {
|
|
168
183
|
return formatter(value)
|
|
@@ -171,15 +186,18 @@ export function useChart(
|
|
|
171
186
|
}
|
|
172
187
|
return value
|
|
173
188
|
}
|
|
189
|
+
|
|
174
190
|
const baseHeightRatio = computed(() => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
191
|
+
const chartHeightRatio = toValue(props.chartHeightRatio)
|
|
192
|
+
const socialMode = toValue(props.socialMode)
|
|
193
|
+
const socialModeRatio = toValue(props.socialModeRatio)
|
|
194
|
+
return chartHeightRatio || (socialMode ? socialModeRatio : 9 / 16)
|
|
179
195
|
})
|
|
196
|
+
|
|
180
197
|
const dataHasHighlights = computed(() => {
|
|
181
|
-
|
|
182
|
-
|
|
198
|
+
const data = toValue(dataRef)
|
|
199
|
+
if (Array.isArray(data)) {
|
|
200
|
+
return some(data, highlighted)
|
|
183
201
|
}
|
|
184
202
|
return false
|
|
185
203
|
})
|
|
@@ -193,6 +211,7 @@ export function useChart(
|
|
|
193
211
|
|
|
194
212
|
return {
|
|
195
213
|
loadedData,
|
|
214
|
+
mounted,
|
|
196
215
|
elementsMaxBBox,
|
|
197
216
|
xAxisYearFormat,
|
|
198
217
|
d3Formatter,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import get from 'lodash/get'
|
|
2
|
+
import first from 'lodash/first'
|
|
3
|
+
|
|
4
|
+
import { Ref, reactive } from 'vue'
|
|
5
|
+
|
|
6
|
+
type ElementMap = {
|
|
7
|
+
[selector: string]: HTMLElement[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type ObserverMap = {
|
|
11
|
+
[selector: string]: MutationObserver
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useQueryObserver(rootRef: Ref<HTMLElement | null>) {
|
|
15
|
+
const elements = reactive<ElementMap>({})
|
|
16
|
+
const observers = reactive<ObserverMap>({})
|
|
17
|
+
|
|
18
|
+
const hasElements = (selector: string): boolean => {
|
|
19
|
+
return get(elements, [selector, 'length'], 0) > 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const hasObserver = (selector: string): boolean => {
|
|
23
|
+
return selector in observers
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const updateElements = (selector: string): HTMLElement[] | null => {
|
|
27
|
+
// We search for the give selector until element are found
|
|
28
|
+
if (rootRef.value && !hasElements(selector)) {
|
|
29
|
+
elements[selector] = Array.from(rootRef.value.querySelectorAll(selector))
|
|
30
|
+
}
|
|
31
|
+
return elements[selector] ?? null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const observerCallback = (selector: string) => {
|
|
35
|
+
return () => {
|
|
36
|
+
updateElements(selector)
|
|
37
|
+
if (hasElements(selector)) {
|
|
38
|
+
observers[selector].disconnect()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const observe = (selector: string) => {
|
|
44
|
+
updateElements(selector)
|
|
45
|
+
// Wait for the root ref to exist and only create the observer once by selector
|
|
46
|
+
if (rootRef.value && !hasObserver(selector)) {
|
|
47
|
+
observers[selector] = new MutationObserver(observerCallback(selector))
|
|
48
|
+
observers[selector].observe(rootRef.value, { childList: true, subtree: true, })
|
|
49
|
+
}
|
|
50
|
+
return observers[selector]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const querySelector = (selector: string) => {
|
|
54
|
+
return first(querySelectorAll(selector))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const querySelectorAll = (selector: string) => {
|
|
58
|
+
observe(selector)
|
|
59
|
+
return get(elements, selector, [])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
querySelector,
|
|
64
|
+
querySelectorAll,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -13,7 +13,6 @@ export function useSendEmail(
|
|
|
13
13
|
referrer?: string | null,
|
|
14
14
|
defaultGroups?: string[] | string
|
|
15
15
|
) {
|
|
16
|
-
const emailValue = toValue(email)
|
|
17
16
|
|
|
18
17
|
const groups = computed(() => {
|
|
19
18
|
return flatten(castArray(defaultGroups).map((g) => g.split(',')))
|
|
@@ -22,6 +21,7 @@ export function useSendEmail(
|
|
|
22
21
|
const urlFromAction = computed(() => {
|
|
23
22
|
return action?.replace('/post?', '/post-json?').concat('&c=?')
|
|
24
23
|
})
|
|
24
|
+
|
|
25
25
|
const parentReferrer = computed(() => {
|
|
26
26
|
if (referrer) {
|
|
27
27
|
return referrer
|
|
@@ -36,6 +36,7 @@ export function useSendEmail(
|
|
|
36
36
|
throw new Error('Missing url Info')
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const emailValue = toValue(email)
|
|
39
40
|
const url = new URL(urlFromAction.value)
|
|
40
41
|
url.searchParams.set('SIGNUP', tracker)
|
|
41
42
|
url.searchParams.set('MMERGE24', parentReferrer.value)
|
|
@@ -44,6 +45,7 @@ export function useSendEmail(
|
|
|
44
45
|
|
|
45
46
|
return url.href
|
|
46
47
|
})
|
|
48
|
+
|
|
47
49
|
function send() {
|
|
48
50
|
return new Promise((resolve, reject) => {
|
|
49
51
|
jsonp(
|
|
@@ -19,11 +19,9 @@ type ColumnBar = {
|
|
|
19
19
|
x: number
|
|
20
20
|
y: number
|
|
21
21
|
}
|
|
22
|
-
//import chart from '../mixins/chart'
|
|
23
22
|
|
|
24
23
|
export default defineComponent({
|
|
25
24
|
name: 'ColumnChart',
|
|
26
|
-
//mixins: [chart],
|
|
27
25
|
props: {
|
|
28
26
|
/**
|
|
29
27
|
* Color of each column (uses the CSS variable --column-color by default)
|
|
@@ -344,6 +342,9 @@ export default defineComponent({
|
|
|
344
342
|
if (!el.value) {
|
|
345
343
|
return
|
|
346
344
|
}
|
|
345
|
+
|
|
346
|
+
d3.select('.column-chart__axis > *').remove()
|
|
347
|
+
|
|
347
348
|
d3.select(el.value)
|
|
348
349
|
.select('.column-chart__axis--x')
|
|
349
350
|
.call(xAxis.value as any)
|
|
@@ -380,6 +381,7 @@ export default defineComponent({
|
|
|
380
381
|
height,
|
|
381
382
|
margin,
|
|
382
383
|
padded,
|
|
384
|
+
isLoaded,
|
|
383
385
|
shownTooltip,
|
|
384
386
|
bars,
|
|
385
387
|
select,
|
|
@@ -399,7 +401,8 @@ export default defineComponent({
|
|
|
399
401
|
'column-chart--has-highlights': dataHasHighlights,
|
|
400
402
|
'column-chart--hover': hover,
|
|
401
403
|
'column-chart--stripped': stripped,
|
|
402
|
-
'column-chart--social-mode': socialMode
|
|
404
|
+
'column-chart--social-mode': socialMode,
|
|
405
|
+
'column-chart--loaded': isLoaded
|
|
403
406
|
}"
|
|
404
407
|
:style="{
|
|
405
408
|
'--column-color': columnColor,
|
|
@@ -493,7 +496,7 @@ export default defineComponent({
|
|
|
493
496
|
|
|
494
497
|
&__columns__item {
|
|
495
498
|
fill: var(--column-color, var(--dark, $dark));
|
|
496
|
-
|
|
499
|
+
|
|
497
500
|
&--highlight {
|
|
498
501
|
fill: var(--column-highlight-color, var(--primary, $primary));
|
|
499
502
|
}
|
|
@@ -529,6 +532,8 @@ export default defineComponent({
|
|
|
529
532
|
left: 0;
|
|
530
533
|
|
|
531
534
|
&__item {
|
|
535
|
+
$tooltip-bg: $body-emphasis-color;
|
|
536
|
+
|
|
532
537
|
display: inline-flex;
|
|
533
538
|
text-align: center;
|
|
534
539
|
flex-direction: row;
|
|
@@ -545,6 +550,7 @@ export default defineComponent({
|
|
|
545
550
|
color: $tooltip-color;
|
|
546
551
|
margin: 0;
|
|
547
552
|
padding: $tooltip-padding-y $tooltip-padding-x;
|
|
553
|
+
|
|
548
554
|
&.fade-enter-active,
|
|
549
555
|
&.fade-leave-active {
|
|
550
556
|
transition: $transition-fade;
|