From 06945ccbcf4e7e7fe901c5e7a4ad83c8a629b59b Mon Sep 17 00:00:00 2001 From: Lyndsi Kay Williams <55605634+lyndsiWilliams@users.noreply.github.com> Date: Tue, 1 Jun 2021 22:47:42 -0500 Subject: [PATCH] feat: Icon Button (#14818) * Creating IconButton * Changed naming: logo is now icon * Hard-coded inset values for ellipses * Removed default SVG * Fixed test * Removed logo from test --- .../IconButton/IconButton.stories.tsx | 58 +++++++++ .../components/IconButton/IconButton.test.jsx | 38 ++++++ .../src/components/IconButton/index.tsx | 123 ++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 superset-frontend/src/components/IconButton/IconButton.stories.tsx create mode 100644 superset-frontend/src/components/IconButton/IconButton.test.jsx create mode 100644 superset-frontend/src/components/IconButton/index.tsx diff --git a/superset-frontend/src/components/IconButton/IconButton.stories.tsx b/superset-frontend/src/components/IconButton/IconButton.stories.tsx new file mode 100644 index 0000000000..45435e70cc --- /dev/null +++ b/superset-frontend/src/components/IconButton/IconButton.stories.tsx @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import IconButton, { IconButtonProps } from '.'; + +export default { + title: 'IconButton', + component: IconButton, +}; + +export const InteractiveIconButton = (args: IconButtonProps) => ( + +); + +InteractiveIconButton.args = { + buttonText: 'This is the IconButton text', + altText: 'This is an example of non-default alt text', + href: 'https://preset.io/', + target: '_blank', +}; + +InteractiveIconButton.argTypes = { + icon: { + defaultValue: '/images/icons/sql.svg', + control: { + type: 'select', + options: [ + '/images/icons/sql.svg', + '/images/icons/server.svg', + '/images/icons/image.svg', + 'Click to see example alt text', + ], + }, + }, +}; diff --git a/superset-frontend/src/components/IconButton/IconButton.test.jsx b/superset-frontend/src/components/IconButton/IconButton.test.jsx new file mode 100644 index 0000000000..4049001195 --- /dev/null +++ b/superset-frontend/src/components/IconButton/IconButton.test.jsx @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { render, screen } from 'spec/helpers/testing-library'; +import IconButton from 'src/components/IconButton'; + +const defaultProps = { + buttonText: 'This is the IconButton text', + icon: '/images/icons/sql.svg', +}; + +describe('IconButton', () => { + it('renders an IconButton', () => { + render(); + + const icon = screen.getByRole('img'); + const buttonText = screen.getByText(/this is the iconbutton text/i); + + expect(icon).toBeVisible(); + expect(buttonText).toBeVisible(); + }); +}); diff --git a/superset-frontend/src/components/IconButton/index.tsx b/superset-frontend/src/components/IconButton/index.tsx new file mode 100644 index 0000000000..e7f9c2d89d --- /dev/null +++ b/superset-frontend/src/components/IconButton/index.tsx @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { styled } from '@superset-ui/core'; +import Button from 'src/components/Button'; +import { ButtonProps as AntdButtonProps } from 'antd/lib/button'; + +export interface IconButtonProps extends AntdButtonProps { + buttonText: string; + icon: string; + altText?: string; +} + +const StyledButton = styled(Button)` + height: auto; + display: flex; + flex-direction: column; + padding: 0; +`; +const StyledImage = styled.div` + margin: ${({ theme }) => theme.gridUnit * 8}px 0; + padding: ${({ theme }) => theme.gridUnit * 4}px; + + &:first-of-type { + margin-right: 0; + } + + img { + width: fit-content; + + &:first-of-type { + margin-right: 0; + } + } +`; + +const StyledInner = styled.div` + max-height: calc(1.5em * 2); + overflow: hidden; + padding-right: 1rem; + position: relative; + white-space: break-spaces; + + &::before { + content: '...'; + inset-block-end: 0; /* "bottom" */ + inset-inline-end: 8px; /* "right" */ + position: absolute; + } + + &::after { + background-color: ${({ theme }) => theme.colors.grayscale.light4}; + content: ''; + height: 1rem; + inset-inline-end: 8px; /* "right" */ + position: absolute; + top: 4px; + width: 1rem; + } +`; + +const StyledBottom = styled.div` + padding: ${({ theme }) => theme.gridUnit * 6}px + ${({ theme }) => theme.gridUnit * 4}px; + border-radius: 0 0 ${({ theme }) => theme.borderRadius}px + ${({ theme }) => theme.borderRadius}px; + background-color: ${({ theme }) => theme.colors.grayscale.light4}; + width: 100%; + line-height: 1.5em; + overflow: hidden; + white-space: no-wrap; + text-overflow: ellipsis; + + &:first-of-type { + margin-right: 0; + } +`; + +const IconButton = styled( + ({ icon, altText, buttonText, ...props }: IconButtonProps) => ( + + + {altText} + + + {buttonText} + + + ), +)` + text-transform: none; + background-color: ${({ theme }) => theme.colors.grayscale.light5}; + font-weight: ${({ theme }) => theme.typography.weights.normal}; + color: ${({ theme }) => theme.colors.grayscale.dark2}; + border: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; + margin: 0; + width: 100%; + + &:hover, + &:focus { + background-color: ${({ theme }) => theme.colors.grayscale.light5}; + color: ${({ theme }) => theme.colors.grayscale.dark2}; + border: 1px solid ${({ theme }) => theme.colors.grayscale.light2}; + } +`; + +export default IconButton;