diff --git a/pages/steps/permutations-annotation.page.tsx b/pages/steps/permutations-annotation.page.tsx new file mode 100644 index 0000000000..6b89c6b3a5 --- /dev/null +++ b/pages/steps/permutations-annotation.page.tsx @@ -0,0 +1,95 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React from 'react'; + +import { Icon } from '~components'; +import Steps, { StepsProps } from '~components/steps'; + +import { SimplePage } from '../app/templates'; +import createPermutations from '../utils/permutations'; +import PermutationsView from '../utils/permutations-view'; + +export const stepsWithAnnotation: ReadonlyArray = [ + { + annotation: , + status: 'log', + header: 'Provided preferences', + }, + { + annotation: , + status: 'success', + statusIconAriaLabel: 'Success', + header: 'Created environment', + details: 'Environment created successfully.', + }, + { + annotation: , + status: 'error', + statusIconAriaLabel: 'Error', + header: 'Validation failed', + details: 'One or more resources could not be validated.', + }, +]; + +export const varyingLengthAnnotationsSteps: ReadonlyArray = [ + { + annotation: , + status: 'log', + header: 'Shorter timestamp', + details: 'This is used to test the shorter timestamp and and we have detail here', + }, + { + annotation: ( + + ), + status: 'log', + details: 'One or more resources could not be validated. A detail in the middle', + header: 'Long timestamp', + }, + { + status: 'loading', + header: 'No annotation yet', + details: 'This is used to test without annotation.', + }, +]; + +const stepsPermutations = createPermutations([ + { + steps: [varyingLengthAnnotationsSteps, stepsWithAnnotation], + ariaLabel: ['test label'], + orientation: ['vertical', 'horizontal'], + renderStep: [ + undefined, + step => ({ + annotation: step.annotation, + header: step.header, + details: step.details && Custom details for {step.details}, + icon: , + }), + step => ({ + annotation: step.annotation, + header: This step header ({step.header}) is wrapped in a custom HTML tag and has very long content, + details: step.details && Custom details for {step.details}, + }), + ], + }, + { + connectorLines: ['none'], + orientation: ['vertical', 'horizontal'], + steps: [varyingLengthAnnotationsSteps], + ariaLabel: ['test label'], + }, +]); + +export default function StepsPermutations() { + return ( + +
{}
} + /> +
+ ); +} diff --git a/pages/steps/playground.page.tsx b/pages/steps/playground.page.tsx new file mode 100644 index 0000000000..ea36b3620d --- /dev/null +++ b/pages/steps/playground.page.tsx @@ -0,0 +1,166 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React, { useState } from 'react'; + +import Checkbox from '~components/checkbox'; +import ColumnLayout from '~components/column-layout'; +import Container from '~components/container'; +import FormField from '~components/form-field'; +import Header from '~components/header'; +import Select from '~components/select'; +import SpaceBetween from '~components/space-between'; +import Steps, { StepsProps } from '~components/steps'; +import Textarea from '~components/textarea'; + +import { SimplePage } from '../app/templates'; + +const statusValues: ReadonlyArray = [ + 'log', + 'success', + 'error', + 'warning', + 'info', + 'loading', + 'in-progress', + 'pending', + 'stopped', + 'not-started', +]; + +const orientationOptions = [ + { label: 'Vertical', value: 'vertical' }, + { label: 'Horizontal', value: 'horizontal' }, +]; + +const defaultStepsJson = JSON.stringify( + [ + { + annotation: '9:00 AM', + header: 'Request received', + status: 'log', + statusIconAriaLabel: 'Log entry', + details: 'The request was added to the activity log.', + }, + { + annotation: '9:05 AM', + header: 'Processing request', + status: 'in-progress', + statusIconAriaLabel: 'In progress', + details: 'The request is being processed.', + }, + { + annotation: '9:10 AM', + header: 'Request completed', + status: 'success', + statusIconAriaLabel: 'Success', + details: 'The request completed successfully.', + }, + ], + null, + 2 +); + +function parseSteps(value: string): { steps: ReadonlyArray; errorText?: string } { + try { + const parsed: unknown = JSON.parse(value); + if (!Array.isArray(parsed)) { + throw new Error('Enter a JSON list of steps.'); + } + + const steps = parsed.map((item, index): StepsProps.Step => { + if (!item || typeof item !== 'object') { + throw new Error(`Step ${index + 1} must be an object.`); + } + + const { annotation, header, status, statusIconAriaLabel, details } = item as Record; + if (typeof header !== 'string') { + throw new Error(`Step ${index + 1} must have a string header.`); + } + if (typeof status !== 'string' || !statusValues.includes(status as StepsProps.Status)) { + throw new Error(`Step ${index + 1} has an invalid status.`); + } + if (annotation !== undefined && typeof annotation !== 'string') { + throw new Error(`Step ${index + 1} annotation must be a string.`); + } + if (details !== undefined && typeof details !== 'string') { + throw new Error(`Step ${index + 1} details must be a string.`); + } + if (statusIconAriaLabel !== undefined && typeof statusIconAriaLabel !== 'string') { + throw new Error(`Step ${index + 1} statusIconAriaLabel must be a string.`); + } + + return { + annotation: annotation === undefined ? undefined : {annotation}, + header: {header}, + details: details === undefined ? undefined : {details}, + status: status as StepsProps.Status, + statusIconAriaLabel, + }; + }); + + return { steps }; + } catch (error) { + return { steps: [], errorText: error instanceof Error ? error.message : 'Invalid JSON.' }; + } +} + +export default function StepsPlayground() { + const [stepsJson, setStepsJson] = useState(defaultStepsJson); + const [orientation, setOrientation] = useState('vertical'); + const [showConnector, setShowConnector] = useState(true); + const [isRtl, setIsRtl] = useState(false); + const { steps, errorText } = parseSteps(stepsJson); + + return ( + + +