Skip to content

Commit

Permalink
Merge pull request #1761 from evidence-dev/table-groups-4real
Browse files Browse the repository at this point in the history
Table Groups & Standalone Delta Component
  • Loading branch information
hughess committed Mar 28, 2024
2 parents ef3aaac + 993c60a commit a2e75a6
Show file tree
Hide file tree
Showing 35 changed files with 3,202 additions and 1,782 deletions.
5 changes: 5 additions & 0 deletions .changeset/nervous-snakes-flow.md
@@ -0,0 +1,5 @@
---
'@evidence-dev/core-components': patch
---

Add table groups and standalone Delta component
40 changes: 40 additions & 0 deletions packages/ui/core-components/src/lib/unsorted/viz/core/Delta.svelte
@@ -0,0 +1,40 @@
<script context="module">
export const evidenceInclude = true;
</script>

<script>
import { QueryLoad } from '../../../atoms/query-load/index.js';
import Delta from './_Delta.svelte';
import EmptyChart from '../core/EmptyChart.svelte';
export let data;
const initialHash = typeof data === 'object' && '__isQueryStore' in data ? data.hash : undefined;
let isInitial = data?.hash === initialHash;
$: isInitial = data?.hash === initialHash;
/** @type {"pass" | "warn" | "error"}*/
export let emptySet = undefined;
/** @type {string}*/
export let emptyMessage = undefined;
let chartType = 'Delta';
// Remove any undefined props (e.g. w/o defaults) to prevent them from being passed
$: spreadProps = Object.fromEntries(Object.entries($$props).filter(([, v]) => v !== undefined));
</script>

<!-- Pass all the props through-->
<QueryLoad {data} let:loaded>
<span slot="empty">
{#if !spreadProps.placeholder}
<EmptyChart {emptyMessage} {emptySet} {chartType} {isInitial} />
{/if}
</span>
<p slot="skeleton" class="text-gray-500">Loading...</p>
<Delta {...spreadProps} data={loaded?.__isQueryStore ? Array.from(loaded) : loaded}>
<slot />
</Delta>
</QueryLoad>
Expand Up @@ -5,6 +5,7 @@
import BigValueError from './BigValueError.svelte';
import Sparkline from './Sparkline.svelte';
import { strictBuild } from '@evidence-dev/component-utilities/chartContext';
import Delta from './Delta.svelte';
export let data;
export let value = null;
export let comparison = null;
Expand All @@ -29,6 +30,8 @@
// Delta controls
export let downIsGood = false;
export let neutralMin = 0;
export let neutralMax = 0;
export let maxWidth = 'none';
export let minWidth = '18%';
Expand Down Expand Up @@ -119,9 +122,16 @@
{#if comparison}
{#if comparisonDelta}
<p class="text-xs font-sans" style={`color:${comparisonColor}`}>
<span class="font-[system-ui]"> {@html positive ? '&#9650;' : '&#9660;'} </span>
<Value {data} column={comparison} fmt={comparisonFmt} />
<span>{comparisonTitle}</span>
<Delta
{data}
column={comparison}
fmt={comparisonFmt}
fontClass="text-xs"
symbolPosition="left"
{neutralMin}
{neutralMax}
text={comparisonTitle}
/>
</p>
{:else}
<p class="text-xs font-sans text-gray-500 pt-[0.5px]">
Expand Down
186 changes: 186 additions & 0 deletions packages/ui/core-components/src/lib/unsorted/viz/core/_Delta.svelte
@@ -0,0 +1,186 @@
<script context="module">
export const evidenceInclude = true;
</script>

<script>
import {
formatValue,
getFormatObjectFromString
} from '@evidence-dev/component-utilities/formatting';
import getColumnSummary from '@evidence-dev/component-utilities/getColumnSummary';
import ValueError from '../core/ValueError.svelte';
import checkInputs from '@evidence-dev/component-utilities/checkInputs';
import { strictBuild } from '@evidence-dev/component-utilities/chartContext';
export let data = undefined;
export let row = 0;
export let column = undefined;
export let value = undefined;
export let text = undefined; // text appearing after the delta (e.g., vs. prev month)
export let chip = false;
$: chip = chip === 'true' || chip === true;
export let downIsGood = false;
$: downIsGood = downIsGood === 'true' || downIsGood === true;
export let fmt = undefined;
export let format_object = undefined;
export let columnUnitSummary = undefined;
export let showValue = true;
$: showValue = showValue === 'true' || showValue === true;
export let showSymbol = true;
$: showSymbol = showSymbol === 'true' || showSymbol === true;
export let symbolPosition = 'right';
export let align = 'right';
export let fontClass = chip ? 'text-sm' : 'text-base';
export let neutralMin = 0;
export let neutralMax = 0;
let colorOptions = {
positive: {
color: downIsGood ? 'var(--red-700)' : 'var(--green-700)',
chipColor: downIsGood ? 'var(--red-100)' : 'var(--green-100)',
chipBorder: downIsGood ? 'var(--red-300)' : 'var(--green-300)'
},
negative: {
color: downIsGood ? 'var(--green-700)' : 'var(--red-700)',
chipColor: downIsGood ? 'var(--green-100)' : 'var(--red-100)',
chipBorder: downIsGood ? 'var(--green-300)' : 'var(--red-300)'
},
neutral: {
color: 'var(--grey-500)',
chipColor: 'var(--grey-100)',
chipBorder: 'var(--grey-300)'
}
};
let error;
let selected_value;
let columnSummary;
let selected_format;
let valueStatus;
$: {
try {
error = undefined;
if (data) {
if (typeof data == 'string') {
throw Error(`Received: data=${data}, expected: data={${data}}`);
}
if (!Array.isArray(data)) {
// Accept bare objects
data = [data];
}
if (isNaN(row)) {
throw Error('row must be a number (row=' + row + ')');
}
try {
Object.keys(data[row])[0];
} catch (e) {
throw Error('Row ' + row + ' does not exist in the dataset');
}
column = column ?? Object.keys(data[row])[0];
checkInputs(data, [column]);
columnSummary = getColumnSummary(data, 'array');
selected_value = data[row][column];
columnSummary = columnSummary.filter((d) => d.id === column);
if (fmt) {
selected_format = getFormatObjectFromString(fmt, columnSummary[0].format.valueType);
} else {
selected_format = columnSummary[0].format;
}
} else if (value) {
if (isNaN(value)) {
throw Error('value must be a number (value=' + value + ')');
} else {
selected_value = value;
selected_format = fmt
? getFormatObjectFromString(fmt, 'number')
: format_object ?? undefined;
}
} else {
throw Error(
'No data or value provided. If you referenced a query result, check that the name is correct.'
);
}
valueStatus =
selected_value > neutralMax
? 'positive'
: selected_value < neutralMin
? 'negative'
: 'neutral';
} catch (e) {
error = e.message;
const setTextRed = '\x1b[31m%s\x1b[0m';
console.error(setTextRed, `Error in Value: ${error}`);
if (strictBuild) {
throw error;
}
}
}
</script>
{#if !error}
<span
class="m-0 {fontClass} font-ui inline-block rounded-md"
style:background-color={chip ? colorOptions[valueStatus].chipColor : undefined}
style:border={chip ? `1px solid ${colorOptions[valueStatus].chipBorder}` : undefined}
style:color={colorOptions[valueStatus].color}
class:px-1={chip}
>
<span style:text-align={align ?? 'right'}>
{#if symbolPosition === 'right'}
{#if showValue}
<span>
{formatValue(selected_value, selected_format, columnUnitSummary)}
</span>
{/if}
{#if showSymbol}
<span class="font-[system-ui]"
>{@html valueStatus === 'positive'
? '&#9650;'
: valueStatus === 'negative'
? '&#9660;'
: '–&thinsp;'}</span
>
{/if}
{:else}
{#if showSymbol}
<span class="font-[system-ui]"
>{@html valueStatus === 'positive'
? '&#9650;'
: valueStatus === 'negative'
? '&#9660;'
: ''}</span
>
{/if}
{#if showValue}
<span>
{formatValue(selected_value, selected_format, columnUnitSummary)}
</span>
{/if}
{/if}
{#if text}
<span>
{text}
</span>
{/if}
</span>
</span>
{:else}
<ValueError {error} />
{/if}
1 change: 1 addition & 0 deletions packages/ui/core-components/src/lib/unsorted/viz/index.js
Expand Up @@ -11,6 +11,7 @@ export { default as CalendarHeatmap } from './heatmap/CalendarHeatmap.svelte';
export { default as Chart } from './core/Chart.svelte';
export { default as Column } from './table/Column.svelte';
export { default as DataTable } from './table/DataTable.svelte';
export { default as Delta } from './core/Delta.svelte';
export { default as EChartsCopyTarget } from './core/EChartsCopyTarget.svelte';
export { default as EChartsMap } from './map/EChartsMap.svelte';
export { default as ECharts } from './core/ECharts.svelte';
Expand Down
Expand Up @@ -62,6 +62,9 @@
export let totalFmt = undefined;
export let weightCol = undefined; // column to use as the weights for weighted average
// Subtotals:
export let subtotalFmt = undefined;
// Color Scale:
export let colorMax = undefined;
export let colorMin = undefined;
Expand All @@ -84,9 +87,12 @@
$: downIsGood = downIsGood === 'true' || downIsGood === true;
export let showValue = true;
$: showValue = showValue === 'true' || showValue === true;
export let deltaSymbol = true;
$: deltaSymbol = deltaSymbol === 'true' || deltaSymbol === true;
export let neutralMin = 0;
export let neutralMax = 0;
export let chip = false;
$: chip = chip === 'true' || chip === true;
$: options = {
id: id,
Expand All @@ -102,9 +108,13 @@
fmt: fmt,
totalAgg: totalAgg,
totalFmt: totalFmt,
subtotalFmt: subtotalFmt,
weightCol: weightCol,
downIsGood: downIsGood,
deltaSymbol: deltaSymbol,
chip: chip,
neutralMin: neutralMin,
neutralMax: neutralMax,
showValue: showValue,
colorMax: colorMax,
colorMin: colorMin,
Expand Down

0 comments on commit a2e75a6

Please sign in to comment.