diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index bfae1036295c..091b5b5d3612 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -61,6 +61,7 @@ window.Row = Row window.FormGroup = FormGroup // isMobile is set at app boot; stub it so components that read it render in Storybook. window.isMobile = false +window.toast = (message) => console.log('[toast]', message) /** @type { import('storybook').Preview } */ const preview = { diff --git a/frontend/common/theme/tokens.json b/frontend/common/theme/tokens.json index 28ecd0fcdb6a..d75701d1ab1f 100644 --- a/frontend/common/theme/tokens.json +++ b/frontend/common/theme/tokens.json @@ -103,7 +103,7 @@ "text": { "default": { "cssVar": "--color-text-default", "light": "#1a2634", "dark": "#ffffff" }, "secondary": { "cssVar": "--color-text-secondary", "light": "#656d7b", "dark": "#9da4ae" }, - "tertiary": { "cssVar": "--color-text-tertiary", "light": "#9da4ae", "dark": "rgba(255, 255, 255, 0.48)" }, + "tertiary": { "cssVar": "--color-text-tertiary", "light": "#656d7b", "dark": "rgba(255, 255, 255, 0.48)", "description": "Placeholders and hint text. In light mode, dark enough to clear 4.5:1 on surface-default." }, "disabled": { "cssVar": "--color-text-disabled", "light": "#9da4ae", "dark": "rgba(255, 255, 255, 0.32)" }, "action": { "cssVar": "--color-text-action", "light": "#6837fc", "dark": "#906af6" }, "danger": { "cssVar": "--color-text-danger", "light": "#bb1720", "dark": "#ef4d56", "description": "In light mode, darker than border/icon danger to clear 4.5:1 on the tint." }, diff --git a/frontend/common/theme/tokens.ts b/frontend/common/theme/tokens.ts index 5caa021f0f54..025e5418cc4c 100644 --- a/frontend/common/theme/tokens.ts +++ b/frontend/common/theme/tokens.ts @@ -206,7 +206,7 @@ export const colorTextDisabled = 'var(--color-text-disabled, #9da4ae)' export const colorTextInfo = 'var(--color-text-info, #0aaddf)' export const colorTextSecondary = 'var(--color-text-secondary, #656d7b)' export const colorTextSuccess = 'var(--color-text-success, #13787b)' -export const colorTextTertiary = 'var(--color-text-tertiary, #9da4ae)' +export const colorTextTertiary = 'var(--color-text-tertiary, #656d7b)' export const colorTextWarning = 'var(--color-text-warning, #9f5208)' // Chart diff --git a/frontend/documentation/TokenReference.generated.stories.tsx b/frontend/documentation/TokenReference.generated.stories.tsx index f0ecbc20aafb..727391c331fc 100644 --- a/frontend/documentation/TokenReference.generated.stories.tsx +++ b/frontend/documentation/TokenReference.generated.stories.tsx @@ -189,7 +189,7 @@ export const AllTokens: StoryObj = { --color-text-tertiary - var(--slate-300) + var(--slate-500) diff --git a/frontend/documentation/components/ValueEditor.stories.tsx b/frontend/documentation/components/ValueEditor.stories.tsx new file mode 100644 index 000000000000..f58af691f279 --- /dev/null +++ b/frontend/documentation/components/ValueEditor.stories.tsx @@ -0,0 +1,94 @@ +import React, { useState } from 'react' +import type { Meta, StoryObj } from 'storybook' + +import ValueEditor from 'components/ValueEditor' +import FieldLabel from 'components/base/forms/FieldLabel' +import Constants from 'common/constants' + +const meta: Meta = { + parameters: { chromatic: { disableSnapshot: false } }, + title: 'Components/Forms/ValueEditor', +} +export default meta + +type Story = StoryObj + +const DEFAULT_TOOLTIP = Constants.strings.REMOTE_CONFIG_DESCRIPTION + +const Interactive = ({ + initialValue = '', + label, + tooltip = DEFAULT_TOOLTIP, + ...props +}: Record) => { + const [value, setValue] = useState(initialValue) + return ( +
+ {label && {label}} + +
+ ) +} + +export const Default: Story = { + render: () => , +} + +export const WithValue: Story = { + render: () => , +} + +export const Multiline: Story = { + render: () => ( + + ), +} + +export const Json: Story = { + render: () => ( + + ), +} + +export const InvalidJson: Story = { + render: () => ( + + ), +} + +export const CodeMedium: Story = { + render: () => ( + + ), +} + +export const Disabled: Story = { + render: () => ( + + ), +} + +export const OnlyOneLang: Story = { + render: () => ( + '} + /> + ), +} diff --git a/frontend/web/components/ValueEditor.js b/frontend/web/components/ValueEditor.js index 0ae271633957..038eb1656d31 100644 --- a/frontend/web/components/ValueEditor.js +++ b/frontend/web/components/ValueEditor.js @@ -1,11 +1,9 @@ import React, { Component } from 'react' import cx from 'classnames' import Highlight from './Highlight' -import ConfigProvider from 'common/providers/ConfigProvider' import { Clipboard } from 'polyfill-react-native' import Icon from './icons/Icon' -import { IonIcon } from '@ionic/react' -import { checkmarkCircle, warning } from 'ionicons/icons' +import BareButton from './base/forms/BareButton' import toml from 'toml' import yaml from 'yaml' @@ -95,23 +93,24 @@ class Validation extends Component { this.props.language === 'ini' ? 'toml' : this.props.language return this.state.error ? ( + > + + } > {`${displayLanguage} validation error, please check your value.
Error: ${this.state.error}`}
) : ( - + > + + ) } } @@ -141,8 +140,17 @@ class ValueEditor extends Component { /> ) + copyValue = () => { + const res = Clipboard.setString(this.props.value) + toast( + res ? 'Clipboard set' : 'Could not set clipboard :(', + res ? '' : 'danger', + ) + } + render() { const { ...rest } = this.props + const showCopy = !this.props.onlyOneLang && !this.props.disabled return (
.yaml {this.state.language === 'yaml' && this.renderValidation()} - { - const res = Clipboard.setString(this.props.value) - toast( - res ? 'Clipboard set' : 'Could not set clipboard :(', - res ? '' : 'danger', - ) - }} - className={cx('txt primary')} - > - - copy - )} + {showCopy && ( + + + + )} + {E2E ? (