From d230092e35cb0836ab2732bed2258c4a7ec31ba6 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Mon, 12 Feb 2024 17:39:26 +0100 Subject: [PATCH 01/12] feat(Table): create a simple version --- .../src/components/Table.tsx | 8 ++ packages/visualizations-react/src/index.tsx | 1 + .../stories/Table/Table.stories.tsx | 91 ++++++++++++++++ .../stories/Table/data.ts | 92 ++++++++++++++++ .../src/components/Table/Body.svelte | 21 ++++ .../src/components/Table/Cell.svelte | 5 + .../src/components/Table/Header.svelte | 15 +++ .../src/components/Table/Table.svelte | 103 ++++++++++++++++++ .../src/components/Table/index.ts | 9 ++ .../src/components/Table/types.ts | 30 +++++ .../src/components/Table/utils/theme.ts | 33 ++++++ packages/visualizations/src/index.ts | 2 + 12 files changed, 410 insertions(+) create mode 100644 packages/visualizations-react/src/components/Table.tsx create mode 100644 packages/visualizations-react/stories/Table/Table.stories.tsx create mode 100644 packages/visualizations-react/stories/Table/data.ts create mode 100644 packages/visualizations/src/components/Table/Body.svelte create mode 100644 packages/visualizations/src/components/Table/Cell.svelte create mode 100644 packages/visualizations/src/components/Table/Header.svelte create mode 100644 packages/visualizations/src/components/Table/Table.svelte create mode 100644 packages/visualizations/src/components/Table/index.ts create mode 100644 packages/visualizations/src/components/Table/types.ts create mode 100644 packages/visualizations/src/components/Table/utils/theme.ts diff --git a/packages/visualizations-react/src/components/Table.tsx b/packages/visualizations-react/src/components/Table.tsx new file mode 100644 index 000000000..a9dfad625 --- /dev/null +++ b/packages/visualizations-react/src/components/Table.tsx @@ -0,0 +1,8 @@ +import { Table as _Table, TableOptions, DataFrame } from '@opendatasoft/visualizations'; +import { FC } from 'react'; +import { Props } from './Props'; +import wrap from './ReactImpl'; + +// Explicit name and type are needed for storybook +const Table: FC> = wrap(_Table); +export default Table; diff --git a/packages/visualizations-react/src/index.tsx b/packages/visualizations-react/src/index.tsx index 2a3bbb97a..d294604af 100644 --- a/packages/visualizations-react/src/index.tsx +++ b/packages/visualizations-react/src/index.tsx @@ -6,3 +6,4 @@ export { default as ChoroplethGeoJson } from './components/ChoroplethGeoJson'; export { default as ChoroplethVectorTiles } from './components/ChoroplethVectorTiles'; export { default as ChoroplethSvg } from './components/ChoroplethSvg'; export { default as PoiMap } from './components/PoiMap'; +export { default as Table } from './components/Table'; diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx new file mode 100644 index 000000000..fe0ae45f3 --- /dev/null +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Column, TableOptions, TableData, Async, Theme } from '@opendatasoft/visualizations'; + +import { Table } from '../../src'; + +import value from './data'; + +const theme: Required = { + textColor: '#000000', + borderColor: '#fcd4cf', + header: { + textColor: '#ffffff', + backgroundColor: '#fd635d', + borderColor: '#f94346', + }, + dataRow: { + activeBackgroundColor: '#f9aea4', + }, +}; + +const meta: ComponentMeta = { + title: 'Table/Table', + component: Table, +}; +export default meta; + +const data: Async = { + value, + loading: false, +}; + +const columns: Column[] = [ + { + title: 'Title', + key: 'title', + }, + { + title: 'Content', + key: 'content', + }, + { + title: 'Published date', + key: 'datePublished', + }, + { + title: 'Featured', + key: 'isFeatured', + }, + { + title: 'Word count', + key: 'wordCount', + }, + { + title: 'Reading time', + key: 'readingTime', + }, + { + title: 'URL', + key: 'url', + }, +]; + +const options: TableOptions = { + columns, + title: 'My table', + subtitle: 'and a subtitle...', + description: 'An aria description', + source: { + href: '', + }, +}; + +const Template: ComponentStory = (args) => ( +
+ {' '} + + +); + +export const Playground = Template.bind({}); +Playground.args = { + data, + options, +}; + +export const CustomTheme = Template.bind({}); +CustomTheme.args = { + data, + options: { ...options, theme }, +}; diff --git a/packages/visualizations-react/stories/Table/data.ts b/packages/visualizations-react/stories/Table/data.ts new file mode 100644 index 000000000..29ab18320 --- /dev/null +++ b/packages/visualizations-react/stories/Table/data.ts @@ -0,0 +1,92 @@ +export default [ + { + title: "Lorem Ipsum Blog Post", + content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.", + datePublished: "2024-02-12", + isFeatured: true, + wordCount: 1200, + readingTime: 5.5, + url: "https://example.com/lorem-ipsum" + }, + { + title: "Pellentesque Nec Blog Post", + content: "Pellentesque nec nisl vitae massa egestas tristique. Mauris auctor consequat justo.", + datePublished: "2024-02-13", + isFeatured: false, + wordCount: 800, + readingTime: 3.8, + url: "https://example.com/pellentesque-nec" + }, + { + title: "Fusce Sit Amet Blog Post", + content: "Fusce sit amet justo vitae libero finibus viverra. Sed tincidunt risus eu tortor fermentum blandit.", + datePublished: "2024-02-14", + isFeatured: true, + wordCount: 1500, + readingTime: 7.2, + url: "https://example.com/fusce-sit-amet" + }, + { + title: "Vestibulum Nec Blog Post", + content: "Vestibulum nec ante non dui cursus fermentum. Suspendisse eu aliquam turpis.", + datePublished: "2024-02-15", + isFeatured: false, + wordCount: 1000, + readingTime: 4.5, + url: "https://example.com/vestibulum-nec" + }, + { + title: "Cras At Blog Post", + content: "Cras at odio eget nisi bibendum aliquam id nec nisl. Donec ultricies nisi vel arcu rhoncus, nec pellentesque mauris aliquam.", + datePublished: "2024-02-16", + isFeatured: true, + wordCount: 1300, + readingTime: 6.0, + url: "https://example.com/cras-at" + }, + { + title: "Quisque A Blog Post", + content: "Quisque a sem sit amet turpis scelerisque volutpat a et arcu. Aenean luctus venenatis ex, non accumsan odio accumsan et.", + datePublished: "2024-02-17", + isFeatured: false, + wordCount: 900, + readingTime: 4.0, + url: "https://example.com/quisque-a" + }, + { + title: "Ut Vitae Blog Post", + content: "Ut vitae eros sit amet felis tincidunt tristique. Nullam non nisi nec justo rhoncus imperdiet.", + datePublished: "2024-02-18", + isFeatured: true, + wordCount: 1100, + readingTime: 5.0, + url: "https://example.com/ut-vitae" + }, + { + title: "Integer Id Blog Post", + content: "Integer id lectus vitae justo euismod finibus. Aliquam a sem at lectus gravida luctus.", + datePublished: "2024-02-19", + isFeatured: false, + wordCount: 950, + readingTime: 4.2, + url: "https://example.com/integer-id" + }, + { + title: "Nam Ullamcorper Blog Post", + content: "Nam ullamcorper semper lacus, ac hendrerit leo tempor nec. Nunc id urna a urna scelerisque viverra sit amet a felis.", + datePublished: "2024-02-20", + isFeatured: true, + wordCount: 1400, + readingTime: 6.5, + url: "https://example.com/nam-ullamcorper" + }, + { + title: "Curabitur Eu Blog Post", + content: "Curabitur eu nisl sit amet nulla luctus cursus eu vel orci. Duis auctor justo vitae nibh rhoncus commodo.", + datePublished: "2024-02-21", + isFeatured: false, + wordCount: 1200, + readingTime: 5.5, + url: "https://example.com/curabitur-eu" + } + ]; diff --git a/packages/visualizations/src/components/Table/Body.svelte b/packages/visualizations/src/components/Table/Body.svelte new file mode 100644 index 000000000..f059eb985 --- /dev/null +++ b/packages/visualizations/src/components/Table/Body.svelte @@ -0,0 +1,21 @@ + + + + {#each records as record} + + {#each columns as column} + + {/each} + + {/each} + diff --git a/packages/visualizations/src/components/Table/Cell.svelte b/packages/visualizations/src/components/Table/Cell.svelte new file mode 100644 index 000000000..5ba1ab4e5 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/visualizations/src/components/Table/Header.svelte b/packages/visualizations/src/components/Table/Header.svelte new file mode 100644 index 000000000..50d4a2bfc --- /dev/null +++ b/packages/visualizations/src/components/Table/Header.svelte @@ -0,0 +1,15 @@ + + + + + {#each columns as column} + + {/each} + + diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte new file mode 100644 index 000000000..2b6e2249f --- /dev/null +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -0,0 +1,103 @@ + + +
+
+ {#if title} +

{title}

+ {/if} + {#if subtitle} +

{subtitle}

+ {/if} +
+
+
{value}
+ {column.title} +
+
+ {#if records} + + {/if} +
+
+ {#if description} +

{description}

+ {/if} + {#if source} + + {/if} + + + diff --git a/packages/visualizations/src/components/Table/index.ts b/packages/visualizations/src/components/Table/index.ts new file mode 100644 index 000000000..4f4cb1d2a --- /dev/null +++ b/packages/visualizations/src/components/Table/index.ts @@ -0,0 +1,9 @@ +import TableImpl from './Table.svelte'; +import SvelteImpl from '../SvelteImpl'; +import type { TableData, TableOptions } from './types'; + +export default class KpiCard extends SvelteImpl { + protected getSvelteComponentClass(): typeof TableImpl { + return TableImpl; + } +} diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts new file mode 100644 index 000000000..de6bd176b --- /dev/null +++ b/packages/visualizations/src/components/Table/types.ts @@ -0,0 +1,30 @@ +import type { DataFrame, Source } from '../types'; + +export type TableData = DataFrame; + +export type Column = { + key: string; + title: string; +}; + +export type Theme = Partial<{ + textColor: string; + borderColor: string; + dataRow: { + activeBackgroundColor: string; + }; + header: { + textColor: string; + backgroundColor: string; + borderColor: string; + }; +}>; + +export type TableOptions = { + columns: Column[]; + title?: string; + subtitle?: string; + description?: string; + source?: Source; + theme?: Theme; +}; diff --git a/packages/visualizations/src/components/Table/utils/theme.ts b/packages/visualizations/src/components/Table/utils/theme.ts new file mode 100644 index 000000000..f32edb380 --- /dev/null +++ b/packages/visualizations/src/components/Table/utils/theme.ts @@ -0,0 +1,33 @@ +import { merge } from 'lodash'; + +import type { TableOptions, Theme } from '../types'; + +const DEFAULT_THEME: Required = { + textColor: '#565656', + borderColor: '#cbd2db', + header: { + textColor: '#142e7b', + backgroundColor: '#f2f3f8', + borderColor: '#dee5ef', + }, + dataRow: { + activeBackgroundColor: '#f6f8fb', + }, +}; + +export default function parseTheme(_theme: TableOptions['theme']) { + const theme: Required = merge(DEFAULT_THEME, _theme); + let style = ''; + const styleObject = { + '--text-color': theme.textColor, + '--border-color': theme.borderColor, + '--active-row-background-color': theme.dataRow.activeBackgroundColor, + '--header-text-color': theme.header.textColor, + '--header-background-color': theme.header.backgroundColor, + '--header-border-color': theme.header.borderColor, + }; + Object.entries(styleObject).forEach(([key, value]) => { + style += `${key}: ${value};\n`; + }); + return style; +} diff --git a/packages/visualizations/src/index.ts b/packages/visualizations/src/index.ts index e9b465837..62a154164 100644 --- a/packages/visualizations/src/index.ts +++ b/packages/visualizations/src/index.ts @@ -4,6 +4,7 @@ export { default as KpiCard } from './components/KpiCard'; export { ChoroplethGeoJson, ChoroplethVectorTiles } from './components/Map/WebGl'; export { default as ChoroplethSvg } from './components/Map/Svg'; export { default as PoiMap } from './components/MapPoi'; +export { default as Table } from './components/Table'; export * from './types'; export * from './components/types'; @@ -13,3 +14,4 @@ export * from './components/Map/types'; export * from './components/MarkdownText/types'; export * from './components/MapPoi/types'; export * from './components/Legend/types'; +export * from './components/Table/types'; From 526680781e883116de1d825e524f8965b319ef5a Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Wed, 21 Feb 2024 16:07:34 +0100 Subject: [PATCH 02/12] style(Table): remove theme prop --- .../stories/Table/Table.stories.tsx | 37 ++++++++++--------- .../src/components/Table/Table.svelte | 18 +++++---- .../src/components/Table/types.ts | 14 ------- .../src/components/Table/utils/theme.ts | 33 ----------------- 4 files changed, 30 insertions(+), 72 deletions(-) delete mode 100644 packages/visualizations/src/components/Table/utils/theme.ts diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx index fe0ae45f3..8c4e82c07 100644 --- a/packages/visualizations-react/stories/Table/Table.stories.tsx +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -1,24 +1,11 @@ import React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Column, TableOptions, TableData, Async, Theme } from '@opendatasoft/visualizations'; +import { Column, TableOptions, TableData, Async } from '@opendatasoft/visualizations'; import { Table } from '../../src'; import value from './data'; -const theme: Required = { - textColor: '#000000', - borderColor: '#fcd4cf', - header: { - textColor: '#ffffff', - backgroundColor: '#fd635d', - borderColor: '#f94346', - }, - dataRow: { - activeBackgroundColor: '#f9aea4', - }, -}; - const meta: ComponentMeta = { title: 'Table/Table', component: Table, @@ -84,8 +71,24 @@ Playground.args = { options, }; -export const CustomTheme = Template.bind({}); -CustomTheme.args = { +const CustomStyleTemplate: ComponentStory = (args) => ( +
+ + +); +export const CustomStyle = CustomStyleTemplate.bind({}); +CustomStyle.args = { data, - options: { ...options, theme }, + options, }; diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index 2b6e2249f..456d1ddaf 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -7,7 +7,6 @@ import SourceLink from '../utils/SourceLink.svelte'; import Header from './Header.svelte'; import Body from './Body.svelte'; - import parseTheme from './utils/theme'; export let data: Async; export let options: TableOptions; @@ -15,14 +14,10 @@ const tableId = `table-${generateId()}`; $: ({ value: records } = data); - // FIXME: Eslint is in conflict with prettier - // eslint-disable-next-line object-curly-newline - $: ({ columns, title, subtitle, description, source, theme } = options); - - $: style = parseTheme(theme); + $: ({ columns, title, subtitle, description, source } = options); -
+
{#if title}

{title}

@@ -53,6 +48,13 @@ --spacing-75: 9px; --spacing-100: 13px; + --text-color: var(--ods-sdk-table-text-color, #565656); + --border-color: var(--ods-sdk-table-border-color, #cbd2db); + --header-text-color: var(--ods-sdk-table-header-text-color, #3c3c3c); + --header-background-color: var(--ods-sdk-table-header-background-color, #f2f3f8); + --header-border-bottom-color: var(--ods-sdk-table-header-border-bottom-color, #dee5ef); + --active-row-background-color: var(--ods-sdk-table-active-row-background-color, #f6f8fb); + /* FIXME: Only using flex style to center source link */ display: flex; flex-wrap: wrap; @@ -88,7 +90,7 @@ background-color: var(--header-background-color); } :global(.container thead) { - border-bottom: 2px solid var(--header-border-color); + border-bottom: 2px solid var(--header-border-bottom-color); } :global(.container tbody tr:not(:last-child)) { border-bottom: 1px solid var(--border-color); diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index de6bd176b..5eb2b00ef 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -7,24 +7,10 @@ export type Column = { title: string; }; -export type Theme = Partial<{ - textColor: string; - borderColor: string; - dataRow: { - activeBackgroundColor: string; - }; - header: { - textColor: string; - backgroundColor: string; - borderColor: string; - }; -}>; - export type TableOptions = { columns: Column[]; title?: string; subtitle?: string; description?: string; source?: Source; - theme?: Theme; }; diff --git a/packages/visualizations/src/components/Table/utils/theme.ts b/packages/visualizations/src/components/Table/utils/theme.ts deleted file mode 100644 index f32edb380..000000000 --- a/packages/visualizations/src/components/Table/utils/theme.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { merge } from 'lodash'; - -import type { TableOptions, Theme } from '../types'; - -const DEFAULT_THEME: Required = { - textColor: '#565656', - borderColor: '#cbd2db', - header: { - textColor: '#142e7b', - backgroundColor: '#f2f3f8', - borderColor: '#dee5ef', - }, - dataRow: { - activeBackgroundColor: '#f6f8fb', - }, -}; - -export default function parseTheme(_theme: TableOptions['theme']) { - const theme: Required = merge(DEFAULT_THEME, _theme); - let style = ''; - const styleObject = { - '--text-color': theme.textColor, - '--border-color': theme.borderColor, - '--active-row-background-color': theme.dataRow.activeBackgroundColor, - '--header-text-color': theme.header.textColor, - '--header-background-color': theme.header.backgroundColor, - '--header-border-color': theme.header.borderColor, - }; - Object.entries(styleObject).forEach(([key, value]) => { - style += `${key}: ${value};\n`; - }); - return style; -} From 128863296143123eb5c567303064d4ac4e2fb0ac Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Wed, 21 Feb 2024 16:21:51 +0100 Subject: [PATCH 03/12] style(Table): prevent horizontal overscroll --- packages/visualizations/src/components/Table/Table.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index 456d1ddaf..8c34c079b 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -71,6 +71,7 @@ border: solid 1px var(--border-color); border-radius: var(--spacing-50); overflow-x: auto; + overscroll-behavior-x: none; max-width: 100%; margin-bottom: var(--spacing-100); } From 5359e865dd00a737414cc9a06fe8dd48e4eb0035 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Wed, 21 Feb 2024 16:37:04 +0100 Subject: [PATCH 04/12] style(Table): table takes all available space --- packages/visualizations/src/components/Table/Table.svelte | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index 8c34c079b..b555c9f25 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -59,6 +59,7 @@ display: flex; flex-wrap: wrap; flex-direction: column; + width: 100%; } .header { margin-bottom: var(--spacing-100); @@ -72,6 +73,7 @@ border-radius: var(--spacing-50); overflow-x: auto; overscroll-behavior-x: none; + width: inherit; max-width: 100%; margin-bottom: var(--spacing-100); } @@ -79,6 +81,7 @@ border-collapse: collapse; color: var(--text-color); white-space: nowrap; + width: inherit; } :global(.container th), :global(.container td) { From 74d1537a5f980e42fe31574d0fa60fe2a57aef45 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 13 Feb 2024 11:46:32 +0100 Subject: [PATCH 05/12] chore: add sass language for svelte style --- packages/visualizations/package-lock.json | 55 ++++++++++++++++++++--- packages/visualizations/package.json | 3 +- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/visualizations/package-lock.json b/packages/visualizations/package-lock.json index 5056d69f9..09da25449 100644 --- a/packages/visualizations/package-lock.json +++ b/packages/visualizations/package-lock.json @@ -55,7 +55,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-svelte3": "^3.2.1", + "eslint-plugin-svelte3": "^3.4.1", "npm-run-all": "^4.1.5", "postcss": "^8.3.11", "prettier": "2.4.1", @@ -66,6 +66,7 @@ "rollup-plugin-svelte": "^6.1.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-visualizer": "^4.2.0", + "sass": "^1.70.0", "svelte": "^3.43.2", "svelte-check": "^2.2.7", "svelte-preprocess": "^4.9.8", @@ -3742,9 +3743,9 @@ } }, "node_modules/eslint-plugin-svelte3": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.2.1.tgz", - "integrity": "sha512-YoBR9mLoKCjGghJ/gvpnFZKaMEu/VRcuxpSRS8KuozuEo7CdBH7bmBHa6FmMm0i4kJnOyx+PVsaptz96K6H/4Q==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.4.1.tgz", + "integrity": "sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==", "dev": true, "engines": { "node": ">=10" @@ -4500,6 +4501,12 @@ "resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz", "integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==" }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, "node_modules/import-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -6899,6 +6906,23 @@ "rimraf": "bin.js" } }, + "node_modules/sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -10773,9 +10797,9 @@ } }, "eslint-plugin-svelte3": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.2.1.tgz", - "integrity": "sha512-YoBR9mLoKCjGghJ/gvpnFZKaMEu/VRcuxpSRS8KuozuEo7CdBH7bmBHa6FmMm0i4kJnOyx+PVsaptz96K6H/4Q==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.4.1.tgz", + "integrity": "sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==", "dev": true, "requires": {} }, @@ -11216,6 +11240,12 @@ "resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-3.1.1.tgz", "integrity": "sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==" }, + "immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, "import-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -12951,6 +12981,17 @@ } } }, + "sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", diff --git a/packages/visualizations/package.json b/packages/visualizations/package.json index 9a4863fd8..51613256d 100644 --- a/packages/visualizations/package.json +++ b/packages/visualizations/package.json @@ -71,7 +71,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-svelte3": "^3.2.1", + "eslint-plugin-svelte3": "^3.4.1", "npm-run-all": "^4.1.5", "postcss": "^8.3.11", "prettier": "2.4.1", @@ -82,6 +82,7 @@ "rollup-plugin-svelte": "^6.1.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-visualizer": "^4.2.0", + "sass": "^1.70.0", "svelte": "^3.43.2", "svelte-check": "^2.2.7", "svelte-preprocess": "^4.9.8", From 237448649ba823becee12ade61a0556609b0f643 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 13 Feb 2024 11:53:10 +0100 Subject: [PATCH 06/12] style(Table): add a unstyled prop Default is false; Is set to true: Remove any presentation style that is applied to the table --- .../stories/Table/Table.stories.tsx | 6 ++ .../src/components/Table/Body.svelte | 13 +++ .../src/components/Table/Cell.svelte | 10 ++ .../src/components/Table/Header.svelte | 15 +++ .../src/components/Table/Table.svelte | 95 ++++++++----------- .../src/components/Table/types.ts | 5 + 6 files changed, 91 insertions(+), 53 deletions(-) diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx index 8c4e82c07..199794092 100644 --- a/packages/visualizations-react/stories/Table/Table.stories.tsx +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -92,3 +92,9 @@ CustomStyle.args = { data, options, }; + +export const Unstyled = Template.bind({}); +Unstyled.args = { + data, + options: { ...options, unstyled: true }, +}; diff --git a/packages/visualizations/src/components/Table/Body.svelte b/packages/visualizations/src/components/Table/Body.svelte index f059eb985..859d3489d 100644 --- a/packages/visualizations/src/components/Table/Body.svelte +++ b/packages/visualizations/src/components/Table/Body.svelte @@ -19,3 +19,16 @@ {/each} + + diff --git a/packages/visualizations/src/components/Table/Cell.svelte b/packages/visualizations/src/components/Table/Cell.svelte index 5ba1ab4e5..1a9a3ce32 100644 --- a/packages/visualizations/src/components/Table/Cell.svelte +++ b/packages/visualizations/src/components/Table/Cell.svelte @@ -3,3 +3,13 @@
+ + diff --git a/packages/visualizations/src/components/Table/Header.svelte b/packages/visualizations/src/components/Table/Header.svelte index 50d4a2bfc..c70881914 100644 --- a/packages/visualizations/src/components/Table/Header.svelte +++ b/packages/visualizations/src/components/Table/Header.svelte @@ -13,3 +13,18 @@ {/each} + + diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index b555c9f25..dd63d2702 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -14,18 +14,23 @@ const tableId = `table-${generateId()}`; $: ({ value: records } = data); - $: ({ columns, title, subtitle, description, source } = options); + // FIXME: Eslint is in conflict with prettier + // eslint-disable-next-line object-curly-newline + $: ({ columns, title, subtitle, description, source, unstyled } = options); + $: defaultStyle = !unstyled; -
-
- {#if title} -

{title}

- {/if} - {#if subtitle} -

{subtitle}

- {/if} -
+
+ {#if title || subtitle} +
+ {#if title} +

{title}

+ {/if} + {#if subtitle} +

{subtitle}

+ {/if} +
+ {/if}
{value}
@@ -42,8 +47,8 @@ {/if} - diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index 5eb2b00ef..85ac5d310 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -13,4 +13,9 @@ export type TableOptions = { subtitle?: string; description?: string; source?: Source; + /** + * Removes all the presentational styles. + * Default is `false`. + */ + unstyled?: boolean; }; From f7db9b8c6903a5be54b7fc8cc6caa0614957661a Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Thu, 22 Feb 2024 16:01:49 +0100 Subject: [PATCH 07/12] chore(Table): update table style Use a lot the :global style element to not scope style. HTML don't have a scoped classname, so it's easier to override the default style. --- .../visualizations-react/.storybook/theme.css | 21 ++++++++++++++++++- .../stories/Table/Table.stories.tsx | 13 +----------- .../src/components/Table/Body.svelte | 14 +++++-------- .../src/components/Table/Cell.svelte | 2 +- .../src/components/Table/Header.svelte | 8 +++---- .../src/components/Table/Table.svelte | 12 +++-------- 6 files changed, 33 insertions(+), 37 deletions(-) diff --git a/packages/visualizations-react/.storybook/theme.css b/packages/visualizations-react/.storybook/theme.css index ac7d04af9..3bf8909a7 100644 --- a/packages/visualizations-react/.storybook/theme.css +++ b/packages/visualizations-react/.storybook/theme.css @@ -16,4 +16,23 @@ h3 { a:link, a:visited, a:active { color: #774936; -} \ No newline at end of file +} + +/* Style for the Custom style Table story */ +.table-story--custom-style .table-wrapper { + border-color: #fcd4cf; +} +.table-story--custom-style thead { + border-bottom-color: #f94346; + border-bottom-width: 2px; + background-color: #fd635d; + color:#ffffff; +} + +.table-story--custom-style tbody tr { + border-bottom-color: #fcd4cf; +} +.table-story--custom-style tbody tr:hover { + background-color: #f9aea4; +} + diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx index 199794092..c728dd8e7 100644 --- a/packages/visualizations-react/stories/Table/Table.stories.tsx +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -72,18 +72,7 @@ Playground.args = { }; const CustomStyleTemplate: ComponentStory = (args) => ( -
+
); diff --git a/packages/visualizations/src/components/Table/Body.svelte b/packages/visualizations/src/components/Table/Body.svelte index 859d3489d..8e657b8fe 100644 --- a/packages/visualizations/src/components/Table/Body.svelte +++ b/packages/visualizations/src/components/Table/Body.svelte @@ -21,14 +21,10 @@ diff --git a/packages/visualizations/src/components/Table/Cell.svelte b/packages/visualizations/src/components/Table/Cell.svelte index 1a9a3ce32..b14f74627 100644 --- a/packages/visualizations/src/components/Table/Cell.svelte +++ b/packages/visualizations/src/components/Table/Cell.svelte @@ -6,7 +6,7 @@ diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index dd63d2702..65b6a15ed 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -53,12 +53,7 @@ --spacing-75: 9px; --spacing-100: 13px; - --text-color: var(--ods-sdk-table-text-color, #565656); - --border-color: var(--ods-sdk-table-border-color, #cbd2db); - --header-text-color: var(--ods-sdk-table-header-text-color, #3c3c3c); - --header-background-color: var(--ods-sdk-table-header-background-color, #f2f3f8); - --header-border-bottom-color: var(--ods-sdk-table-header-border-bottom-color, #dee5ef); - --active-row-background-color: var(--ods-sdk-table-active-row-background-color, #f6f8fb); + --border-color: #cbd2db; /* FIXME: Only using flex style to center source link */ display: flex; @@ -71,7 +66,7 @@ display: none; } - .ods-dataviz-sdk-table--default { + :global(.ods-dataviz-sdk-table--default) { .dataviz-header { margin-bottom: var(--spacing-100); h3, @@ -79,7 +74,7 @@ margin: 0; } } - .table-wrapper { + :global(.table-wrapper) { border: solid 1px var(--border-color); border-radius: var(--spacing-50); overflow-x: auto; @@ -89,7 +84,6 @@ margin-bottom: var(--spacing-100); table { border-collapse: collapse; - color: var(--text-color); white-space: nowrap; width: inherit; } From 2b01b4651324b1a732726875f3b989757585592b Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 13 Feb 2024 17:57:42 +0100 Subject: [PATCH 08/12] feat(Table): format cell content --- .../stories/Table/Table.stories.tsx | 36 ++++++++++-- .../stories/Table/data.ts | 31 ++++++----- .../src/components/Table/Body.svelte | 8 +-- .../src/components/Table/Cell.svelte | 15 ----- .../src/components/Table/Cell/Cell.svelte | 54 ++++++++++++++++++ .../Table/Cell/Format/BooleanFormat.svelte | 17 ++++++ .../Table/Cell/Format/DateFormat.svelte | 22 ++++++++ .../Table/Cell/Format/NumberFormat.svelte | 19 +++++++ .../Table/Cell/Format/TextFormat.svelte | 16 ++++++ .../Table/Cell/Format/URLFormat.svelte | 25 +++++++++ .../src/components/Table/Cell/Format/index.ts | 9 +++ .../src/components/Table/Cell/Format/utils.ts | 8 +++ .../src/components/Table/Cell/index.ts | 3 + .../src/components/Table/Header.svelte | 5 +- .../src/components/Table/constants.ts | 9 +++ .../src/components/Table/types.ts | 55 ++++++++++++++++++- 16 files changed, 289 insertions(+), 43 deletions(-) delete mode 100644 packages/visualizations/src/components/Table/Cell.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Cell.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/index.ts create mode 100644 packages/visualizations/src/components/Table/Cell/Format/utils.ts create mode 100644 packages/visualizations/src/components/Table/Cell/index.ts create mode 100644 packages/visualizations/src/components/Table/constants.ts diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx index c728dd8e7..13b1c9d88 100644 --- a/packages/visualizations-react/stories/Table/Table.stories.tsx +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -21,30 +21,47 @@ const columns: Column[] = [ { title: 'Title', key: 'title', + dataFormat: 'short-text', + }, + { + title: 'Price', + key: 'price', + dataFormat: 'number', + options: { + style: 'currency', + currency: 'EUR', + }, }, { title: 'Content', key: 'content', + dataFormat: 'long-text', }, { title: 'Published date', key: 'datePublished', + dataFormat: 'date', + options: { dateStyle: 'full' }, }, { title: 'Featured', key: 'isFeatured', + dataFormat: 'boolean', }, { title: 'Word count', key: 'wordCount', + dataFormat: 'number', }, { title: 'Reading time', key: 'readingTime', + dataFormat: 'number', }, { title: 'URL', key: 'url', + dataFormat: 'url', }, ]; @@ -58,12 +75,7 @@ const options: TableOptions = { }, }; -const Template: ComponentStory = (args) => ( -
- {' '} -
- -); +const Template: ComponentStory = (args) =>
; export const Playground = Template.bind({}); Playground.args = { @@ -82,6 +94,18 @@ CustomStyle.args = { options, }; +const ScrollTemplate: ComponentStory = (args) => ( +
+
+ +); + +export const Scroll = ScrollTemplate.bind({}); +Scroll.args = { + data, + options, +}; + export const Unstyled = Template.bind({}); Unstyled.args = { data, diff --git a/packages/visualizations-react/stories/Table/data.ts b/packages/visualizations-react/stories/Table/data.ts index 29ab18320..694f05ab2 100644 --- a/packages/visualizations-react/stories/Table/data.ts +++ b/packages/visualizations-react/stories/Table/data.ts @@ -1,6 +1,7 @@ export default [ { title: "Lorem Ipsum Blog Post", + price: 12, content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.", datePublished: "2024-02-12", isFeatured: true, @@ -10,6 +11,7 @@ export default [ }, { title: "Pellentesque Nec Blog Post", + price: 10.75, content: "Pellentesque nec nisl vitae massa egestas tristique. Mauris auctor consequat justo.", datePublished: "2024-02-13", isFeatured: false, @@ -19,6 +21,7 @@ export default [ }, { title: "Fusce Sit Amet Blog Post", + price: 1100, content: "Fusce sit amet justo vitae libero finibus viverra. Sed tincidunt risus eu tortor fermentum blandit.", datePublished: "2024-02-14", isFeatured: true, @@ -28,6 +31,7 @@ export default [ }, { title: "Vestibulum Nec Blog Post", + price: 0, content: "Vestibulum nec ante non dui cursus fermentum. Suspendisse eu aliquam turpis.", datePublished: "2024-02-15", isFeatured: false, @@ -37,6 +41,7 @@ export default [ }, { title: "Cras At Blog Post", + price: 1, content: "Cras at odio eget nisi bibendum aliquam id nec nisl. Donec ultricies nisi vel arcu rhoncus, nec pellentesque mauris aliquam.", datePublished: "2024-02-16", isFeatured: true, @@ -46,6 +51,7 @@ export default [ }, { title: "Quisque A Blog Post", + price: 0.99, content: "Quisque a sem sit amet turpis scelerisque volutpat a et arcu. Aenean luctus venenatis ex, non accumsan odio accumsan et.", datePublished: "2024-02-17", isFeatured: false, @@ -55,6 +61,7 @@ export default [ }, { title: "Ut Vitae Blog Post", + price: 10, content: "Ut vitae eros sit amet felis tincidunt tristique. Nullam non nisi nec justo rhoncus imperdiet.", datePublished: "2024-02-18", isFeatured: true, @@ -64,6 +71,7 @@ export default [ }, { title: "Integer Id Blog Post", + price: 5, content: "Integer id lectus vitae justo euismod finibus. Aliquam a sem at lectus gravida luctus.", datePublished: "2024-02-19", isFeatured: false, @@ -72,21 +80,16 @@ export default [ url: "https://example.com/integer-id" }, { - title: "Nam Ullamcorper Blog Post", - content: "Nam ullamcorper semper lacus, ac hendrerit leo tempor nec. Nunc id urna a urna scelerisque viverra sit amet a felis.", - datePublished: "2024-02-20", - isFeatured: true, - wordCount: 1400, - readingTime: 6.5, - url: "https://example.com/nam-ullamcorper" + title: "Undefined row", + price: undefined, + content: undefined, + datePublished: undefined, + isFeatured: undefined, + wordCount: undefined, + readingTime: undefined, + url: undefined }, { - title: "Curabitur Eu Blog Post", - content: "Curabitur eu nisl sit amet nulla luctus cursus eu vel orci. Duis auctor justo vitae nibh rhoncus commodo.", - datePublished: "2024-02-21", - isFeatured: false, - wordCount: 1200, - readingTime: 5.5, - url: "https://example.com/curabitur-eu" + title: "Empty row" } ]; diff --git a/packages/visualizations/src/components/Table/Body.svelte b/packages/visualizations/src/components/Table/Body.svelte index 8e657b8fe..61e4178f2 100644 --- a/packages/visualizations/src/components/Table/Body.svelte +++ b/packages/visualizations/src/components/Table/Body.svelte @@ -1,10 +1,6 @@ - - - - diff --git a/packages/visualizations/src/components/Table/Cell/Cell.svelte b/packages/visualizations/src/components/Table/Cell/Cell.svelte new file mode 100644 index 000000000..5ee64b15f --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Cell.svelte @@ -0,0 +1,54 @@ + + + + + diff --git a/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte new file mode 100644 index 000000000..ee2d3e23b --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte @@ -0,0 +1,17 @@ + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte new file mode 100644 index 000000000..b875b739d --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte @@ -0,0 +1,22 @@ + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte new file mode 100644 index 000000000..91f935af1 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte @@ -0,0 +1,19 @@ + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte new file mode 100644 index 000000000..2d3bee906 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte @@ -0,0 +1,16 @@ + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte new file mode 100644 index 000000000..ceb43ecd9 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte @@ -0,0 +1,25 @@ + + +{#if value} + {value} +{:else} + {rawValue} +{/if} diff --git a/packages/visualizations/src/components/Table/Cell/Format/index.ts b/packages/visualizations/src/components/Table/Cell/Format/index.ts new file mode 100644 index 000000000..6c96f64e3 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/index.ts @@ -0,0 +1,9 @@ +import BooleanFormat from './BooleanFormat.svelte'; +import DateFormat from './DateFormat.svelte'; +import NumberFormat from './NumberFormat.svelte'; +import TextFormat from './TextFormat.svelte'; +import URLFormat from './URLFormat.svelte'; +import { isValidRawValue } from './utils'; + +export default { BooleanFormat, DateFormat, NumberFormat, TextFormat, URLFormat }; +export { isValidRawValue }; diff --git a/packages/visualizations/src/components/Table/Cell/Format/utils.ts b/packages/visualizations/src/components/Table/Cell/Format/utils.ts new file mode 100644 index 000000000..c31a8709e --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/utils.ts @@ -0,0 +1,8 @@ +export function isValidRawValue(rawValue: unknown): boolean { + return rawValue !== undefined && rawValue !== null; +} + +export function warn(value: unknown, format: string) { + // eslint-disable-next-line no-console + console.warn(`ODS Dataviz SDK - Table: ${value} is not a valid ${format}`); +} diff --git a/packages/visualizations/src/components/Table/Cell/index.ts b/packages/visualizations/src/components/Table/Cell/index.ts new file mode 100644 index 000000000..038973c32 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/index.ts @@ -0,0 +1,3 @@ +import Cell from './Cell.svelte'; + +export default Cell; diff --git a/packages/visualizations/src/components/Table/Header.svelte b/packages/visualizations/src/components/Table/Header.svelte index b05efef8c..7b11e2b6c 100644 --- a/packages/visualizations/src/components/Table/Header.svelte +++ b/packages/visualizations/src/components/Table/Header.svelte @@ -7,7 +7,7 @@ {#each columns as column} - {/each} @@ -23,6 +23,9 @@ padding: var(--spacing-75); font-weight: normal; text-align: left; + &.table-header--number { + text-align: right; + } } } diff --git a/packages/visualizations/src/components/Table/constants.ts b/packages/visualizations/src/components/Table/constants.ts new file mode 100644 index 000000000..e78d688d4 --- /dev/null +++ b/packages/visualizations/src/components/Table/constants.ts @@ -0,0 +1,9 @@ +// eslint-disable-next-line import/prefer-default-export +export const DATA_FORMAT = { + longText: 'long-text', + shortText: 'short-text', + date: 'date', + number: 'number', + boolean: 'boolean', + url: 'url', +} as const; diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index 85ac5d310..a49681c09 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -1,12 +1,65 @@ import type { DataFrame, Source } from '../types'; +import type { DATA_FORMAT } from './constants'; + +type DataFormatKey = keyof typeof DATA_FORMAT; +export type DataFormat = typeof DATA_FORMAT[DataFormatKey]; export type TableData = DataFrame; -export type Column = { +type BaseColumn = { key: string; title: string; }; +export type ShortTextColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.shortText; +}; + +export type LongTextColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.longText; +}; + +export type NumberColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.number; + /** + * Number formatting options + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options + */ + options?: Intl.NumberFormatOptions; +}; + +export type DateColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.date; + /** + * Date and time formatting options + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#using_options + */ + options?: Intl.DateTimeFormatOptions; +}; + +export type BooleanColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.boolean; +}; + +/** + * Render HTML \ tag if the record value is a valid URL. + */ +export type URLColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.url; + /** Default is `_blank` */ + target?: string; +}; + +export type Column = + | ShortTextColumn + | LongTextColumn + | NumberColumn + | DateColumn + | BooleanColumn + | URLColumn; + export type TableOptions = { columns: Column[]; title?: string; From c02079e73b7038f6599c759be948341f2e558b40 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 20 Feb 2024 15:45:38 +0100 Subject: [PATCH 09/12] style(Table): Update style for short and long text --- .../src/components/Table/Cell/Cell.svelte | 19 ++++++++------- .../Table/Cell/Format/TextFormat.svelte | 24 ++++++++++++++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/visualizations/src/components/Table/Cell/Cell.svelte b/packages/visualizations/src/components/Table/Cell/Cell.svelte index 5ee64b15f..51fb4a19f 100644 --- a/packages/visualizations/src/components/Table/Cell/Cell.svelte +++ b/packages/visualizations/src/components/Table/Cell/Cell.svelte @@ -6,10 +6,15 @@ export let rawValue: unknown; export let column: Column; + const title = + ['short-text', 'long-text'].includes(column.dataFormat) && typeof rawValue === 'string' + ? rawValue + : undefined; + $: ({ dataFormat } = column); - @@ -36,17 +41,13 @@ &--number { text-align: right; } - // FIXME: Arbitrary style; to be refined later &--short-text, &--url { text-overflow: ellipsis; overflow: hidden; - max-width: 150px; - } - &--long-text { - min-width: 300px; - max-width: 500px; - white-space: initial; + width: max-content; + min-width: 40px; + max-width: 240px; } } } diff --git a/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte index 2d3bee906..65a27c07a 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte @@ -1,7 +1,9 @@ -{value} +{#if format === 'long-text'} + +
{value}
+{:else} + {value} +{/if} + + From 2eff5d1bc1f4f82ec2218a9b5ba0e37226242c77 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Thu, 22 Feb 2024 18:20:00 +0100 Subject: [PATCH 10/12] chore(Table): update components organization --- .../stories/Table/data.ts | 6 +- .../src/components/Table/Body.svelte | 9 -- .../src/components/Table/Cell/Cell.svelte | 46 +--------- .../Table/Cell/Format/BooleanFormat.svelte | 2 + .../Table/Cell/Format/LongTextFormat.svelte | 19 ++++ .../Table/Cell/Format/ShortTextFormat.svelte | 18 ++++ .../Table/Cell/Format/TextFormat.svelte | 38 -------- .../Table/Cell/Format/URLFormat.svelte | 5 +- .../src/components/Table/Cell/Format/index.ts | 14 ++- .../src/components/Table/Header.svelte | 16 ---- .../src/components/Table/Table.svelte | 42 +-------- .../src/components/Table/index.scss | 89 +++++++++++++++++++ .../src/components/Table/types.ts | 9 +- 13 files changed, 158 insertions(+), 155 deletions(-) create mode 100644 packages/visualizations/src/components/Table/Cell/Format/LongTextFormat.svelte create mode 100644 packages/visualizations/src/components/Table/Cell/Format/ShortTextFormat.svelte delete mode 100644 packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte create mode 100644 packages/visualizations/src/components/Table/index.scss diff --git a/packages/visualizations-react/stories/Table/data.ts b/packages/visualizations-react/stories/Table/data.ts index 694f05ab2..35af60fc5 100644 --- a/packages/visualizations-react/stories/Table/data.ts +++ b/packages/visualizations-react/stories/Table/data.ts @@ -82,11 +82,11 @@ export default [ { title: "Undefined row", price: undefined, - content: undefined, + content: null, datePublished: undefined, - isFeatured: undefined, + isFeatured: null, wordCount: undefined, - readingTime: undefined, + readingTime: null, url: undefined }, { diff --git a/packages/visualizations/src/components/Table/Body.svelte b/packages/visualizations/src/components/Table/Body.svelte index 61e4178f2..c80dd9571 100644 --- a/packages/visualizations/src/components/Table/Body.svelte +++ b/packages/visualizations/src/components/Table/Body.svelte @@ -15,12 +15,3 @@
{/each} - - diff --git a/packages/visualizations/src/components/Table/Cell/Cell.svelte b/packages/visualizations/src/components/Table/Cell/Cell.svelte index 51fb4a19f..2530c8b8a 100644 --- a/packages/visualizations/src/components/Table/Cell/Cell.svelte +++ b/packages/visualizations/src/components/Table/Cell/Cell.svelte @@ -6,50 +6,12 @@ export let rawValue: unknown; export let column: Column; - const title = - ['short-text', 'long-text'].includes(column.dataFormat) && typeof rawValue === 'string' - ? rawValue - : undefined; - - $: ({ dataFormat } = column); + $: ({ dataFormat, options = {} } = column); - - - diff --git a/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte index ee2d3e23b..c5fd1bbd3 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/BooleanFormat.svelte @@ -2,6 +2,8 @@ import { warn } from './utils'; export let rawValue: unknown; + // svelte-ignore unused-export-let + export let options = {}; function getDisplayValue(v: unknown) { if (typeof v !== 'boolean') { diff --git a/packages/visualizations/src/components/Table/Cell/Format/LongTextFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/LongTextFormat.svelte new file mode 100644 index 000000000..7b418f1f2 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/LongTextFormat.svelte @@ -0,0 +1,19 @@ + + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/ShortTextFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/ShortTextFormat.svelte new file mode 100644 index 000000000..aa7610868 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/ShortTextFormat.svelte @@ -0,0 +1,18 @@ + + +{value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte deleted file mode 100644 index 65a27c07a..000000000 --- a/packages/visualizations/src/components/Table/Cell/Format/TextFormat.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - -{#if format === 'long-text'} - -
{value}
-{:else} - {value} -{/if} - - diff --git a/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte index ceb43ecd9..a07daaa84 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/URLFormat.svelte @@ -1,8 +1,9 @@ {#if value} -
{value} + {value} {:else} {rawValue} {/if} diff --git a/packages/visualizations/src/components/Table/Cell/Format/index.ts b/packages/visualizations/src/components/Table/Cell/Format/index.ts index 6c96f64e3..7c6c60fb8 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/index.ts +++ b/packages/visualizations/src/components/Table/Cell/Format/index.ts @@ -1,9 +1,19 @@ import BooleanFormat from './BooleanFormat.svelte'; import DateFormat from './DateFormat.svelte'; import NumberFormat from './NumberFormat.svelte'; -import TextFormat from './TextFormat.svelte'; import URLFormat from './URLFormat.svelte'; +import ShortTextFormat from './ShortTextFormat.svelte'; +import LongTextFormat from './LongTextFormat.svelte'; import { isValidRawValue } from './utils'; -export default { BooleanFormat, DateFormat, NumberFormat, TextFormat, URLFormat }; +const Format = { + boolean: BooleanFormat, + date: DateFormat, + 'short-text': ShortTextFormat, + 'long-text': LongTextFormat, + url: URLFormat, + number: NumberFormat, +}; + export { isValidRawValue }; +export default Format; diff --git a/packages/visualizations/src/components/Table/Header.svelte b/packages/visualizations/src/components/Table/Header.svelte index 7b11e2b6c..2bb222d6a 100644 --- a/packages/visualizations/src/components/Table/Header.svelte +++ b/packages/visualizations/src/components/Table/Header.svelte @@ -13,19 +13,3 @@ {/each} - - diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index 65b6a15ed..ce1cf2232 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -48,45 +48,5 @@ diff --git a/packages/visualizations/src/components/Table/index.scss b/packages/visualizations/src/components/Table/index.scss new file mode 100644 index 000000000..0fc41cc20 --- /dev/null +++ b/packages/visualizations/src/components/Table/index.scss @@ -0,0 +1,89 @@ +.ods-dataviz-sdk-table { + --spacing-50: 6px; + --spacing-75: 9px; + --spacing-100: 13px; + + --border-color: #cbd2db; + + /* FIXME: Only using flex style to center source link */ + display: flex; + flex-wrap: wrap; + flex-direction: column; + width: 100%; +} + +.dataviz-header { + margin-bottom: var(--spacing-100); + h3, + p { + margin: 0; + } +} + +/* Suitable for elements that are used via aria-describedby or aria-labelledby */ +.a11y-invisible-description { + display: none; +} + +// Default Table visual style. Not applied if 'unstyled' prop is set. +:global(.ods-dataviz-sdk-table--default) { + :global(.table-wrapper) { + border: solid 1px var(--border-color); + border-radius: var(--spacing-50); + overflow-x: auto; + overscroll-behavior-x: none; + max-width: 100%; + width: inherit; + margin-bottom: var(--spacing-100); + + :global(table) { + border-collapse: collapse; + white-space: nowrap; + width: inherit; + } + :global(thead) { + border-bottom: 1px solid var(--border-color); + } + } + + :global(tbody td), + :global(th) { + text-align: left; + padding: var(--spacing-75); + } + :global(tbody tr) { + border-bottom: 1px solid var(--border-color); + } + :global(tbody tr:last-child) { + border-bottom: none; + } +} + +// Data formatting style +:global(.ods-dataviz-sdk-table) { + // Table header + :global(.table-header--number) { + text-align: right; + } + + // Table data + :global(.table-data--long-text > span), + :global(.table-data--short-text), + :global(.table-data--url) { + text-overflow: ellipsis; + overflow: hidden; + width: max-content; + min-width: 40px; + max-width: 240px; + } + :global(.table-data--long-text > span) { + display: -webkit-box; + -webkit-line-clamp: 3; + line-clamp: 3; + -webkit-box-orient: vertical; + white-space: pre-wrap; + } + :global(.table-data--number) { + text-align: right; + } +} diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index a49681c09..a67a3e396 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -13,10 +13,12 @@ type BaseColumn = { export type ShortTextColumn = BaseColumn & { dataFormat: typeof DATA_FORMAT.shortText; + options?: never; }; export type LongTextColumn = BaseColumn & { dataFormat: typeof DATA_FORMAT.longText; + options?: never; }; export type NumberColumn = BaseColumn & { @@ -41,6 +43,7 @@ export type DateColumn = BaseColumn & { export type BooleanColumn = BaseColumn & { dataFormat: typeof DATA_FORMAT.boolean; + options?: never; }; /** @@ -48,8 +51,10 @@ export type BooleanColumn = BaseColumn & { */ export type URLColumn = BaseColumn & { dataFormat: typeof DATA_FORMAT.url; - /** Default is `_blank` */ - target?: string; + options?: { + /** Default is `_blank` */ + target?: string; + }; }; export type Column = From 756dfcdb9694d22efa15bd69cf24e48a3e1a1885 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Fri, 23 Feb 2024 16:09:20 +0100 Subject: [PATCH 11/12] style(Table): update scoped classname --- packages/visualizations/src/components/Table/Table.svelte | 2 +- packages/visualizations/src/components/Table/index.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index ce1cf2232..7e89a1225 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -22,7 +22,7 @@
{#if title || subtitle} -
+
{#if title}

{title}

{/if} diff --git a/packages/visualizations/src/components/Table/index.scss b/packages/visualizations/src/components/Table/index.scss index 0fc41cc20..2a01f94ae 100644 --- a/packages/visualizations/src/components/Table/index.scss +++ b/packages/visualizations/src/components/Table/index.scss @@ -12,7 +12,7 @@ width: 100%; } -.dataviz-header { +.header { margin-bottom: var(--spacing-100); h3, p { From 2f6f403570c286f0a96003a1414cbdd529831dc4 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Wed, 14 Feb 2024 17:47:57 +0100 Subject: [PATCH 12/12] feat(Table): add locale props To format number and dates according to the locale. Default locale comes from the navigator language. --- .../stories/Table/Table.stories.tsx | 1 + .../Table/Cell/Format/DateFormat.svelte | 8 +++++--- .../Table/Cell/Format/NumberFormat.svelte | 8 +++++--- .../src/components/Table/Table.svelte | 4 +++- .../src/components/Table/store.ts | 17 +++++++++++++++++ .../src/components/Table/types.ts | 2 ++ 6 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 packages/visualizations/src/components/Table/store.ts diff --git a/packages/visualizations-react/stories/Table/Table.stories.tsx b/packages/visualizations-react/stories/Table/Table.stories.tsx index 13b1c9d88..9f841895c 100644 --- a/packages/visualizations-react/stories/Table/Table.stories.tsx +++ b/packages/visualizations-react/stories/Table/Table.stories.tsx @@ -73,6 +73,7 @@ const options: TableOptions = { source: { href: '', }, + locale: 'fr', }; const Template: ComponentStory = (args) =>
{value} + + {#if isValidRawValue(rawValue)} + {#if column.dataFormat === 'url'} + + {:else if column.dataFormat === 'number'} + + {:else if column.dataFormat === 'date'} + + {:else if column.dataFormat === 'boolean'} + + {:else if column.dataFormat === 'long-text' || column.dataFormat === 'short-text'} + + {/if} + {/if} +
+ {column.title} + {#if isValidRawValue(rawValue)} {#if column.dataFormat === 'url'} @@ -21,7 +26,7 @@ {:else if column.dataFormat === 'boolean'} {:else if column.dataFormat === 'long-text' || column.dataFormat === 'short-text'} - + {/if} {/if}
- + + {#if isValidRawValue(rawValue)} - {#if column.dataFormat === 'url'} - - {:else if column.dataFormat === 'number'} - - {:else if column.dataFormat === 'date'} - - {:else if column.dataFormat === 'boolean'} - - {:else if column.dataFormat === 'long-text' || column.dataFormat === 'short-text'} - - {/if} + {/if}
; diff --git a/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte index b875b739d..648d6e2e2 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/DateFormat.svelte @@ -1,22 +1,24 @@ {value} diff --git a/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte index 91f935af1..63c2be33b 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/NumberFormat.svelte @@ -1,19 +1,21 @@ {value} diff --git a/packages/visualizations/src/components/Table/Table.svelte b/packages/visualizations/src/components/Table/Table.svelte index 7e89a1225..fd4bda401 100644 --- a/packages/visualizations/src/components/Table/Table.svelte +++ b/packages/visualizations/src/components/Table/Table.svelte @@ -7,6 +7,7 @@ import SourceLink from '../utils/SourceLink.svelte'; import Header from './Header.svelte'; import Body from './Body.svelte'; + import { updateLocale } from './store'; export let data: Async; export let options: TableOptions; @@ -16,8 +17,9 @@ $: ({ value: records } = data); // FIXME: Eslint is in conflict with prettier // eslint-disable-next-line object-curly-newline - $: ({ columns, title, subtitle, description, source, unstyled } = options); + $: ({ columns, title, subtitle, description, source, unstyled, locale } = options); $: defaultStyle = !unstyled; + $: updateLocale(locale);
diff --git a/packages/visualizations/src/components/Table/store.ts b/packages/visualizations/src/components/Table/store.ts new file mode 100644 index 000000000..89fb1edce --- /dev/null +++ b/packages/visualizations/src/components/Table/store.ts @@ -0,0 +1,17 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { writable } from 'svelte/store'; + +type TableStore = { + locale: string; +}; + +const defaultLocale = navigator.language; + +const store = writable({ locale: defaultLocale }); + +const updateLocale = (locale: string = defaultLocale) => { + store.update((previousValue) => ({ ...previousValue, locale })); +}; + +export { updateLocale }; +export default store; diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index a67a3e396..6d826eb0d 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -71,6 +71,8 @@ export type TableOptions = { subtitle?: string; description?: string; source?: Source; + /** To format date and number with the right locale. Default is from browser language */ + locale?: string; /** * Removes all the presentational styles. * Default is `false`.