mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-02 19:45:51 +01:00
Move frontendcomponents into ui-core
The new architecture has been implemented. Co-authored-by: Eduard Heimbuch<eduard.heimbuch@cloudogu.com> Committed-by: Eduard Heimbuch<eduard.heimbuch@cloudogu.com> Pushed-by: Tarik Gürsoy<tarik.guersoy@cloudogu.com> Committed-by: Tarik Gürsoy<tarik.guersoy@cloudogu.com> Pushed-by: Eduard Heimbuch<eduard.heimbuch@cloudogu.com> Co-authored-by: Tarik Gürsoy<tarik.guersoy@cloudogu.com> Reviewed-by: Konstantin Schaper <konstantin.schaper@cloudogu.com>
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"presets": ["@scm-manager/babel-preset"],
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"]
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
class RemoveThemesPlugin {
|
||||
apply (compiler) {
|
||||
compiler.hooks.compilation.tap('RemoveThemesPlugin', (compilation) => {
|
||||
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(
|
||||
'RemoveThemesPlugin',
|
||||
(data, cb) => {
|
||||
|
||||
// remove generated style-loader bundles from the page
|
||||
// there should be a better way, which does not generate the bundles at all
|
||||
// but for now it works
|
||||
if (data.assets.js) {
|
||||
data.assets.js = data.assets.js.filter(bundle => !bundle.startsWith("ui-theme-"))
|
||||
.filter(bundle => !bundle.startsWith("runtime~ui-theme-"))
|
||||
}
|
||||
|
||||
// remove css links to avoid conflicts with the themes
|
||||
// so we remove all and add our own via preview-head.html
|
||||
if (data.assets.css) {
|
||||
data.assets.css = data.assets.css.filter(css => !css.startsWith("ui-theme-"))
|
||||
}
|
||||
|
||||
// Tell webpack to move on
|
||||
cb(null, data)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RemoveThemesPlugin
|
||||
@@ -1,26 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-->
|
||||
|
||||
<link id="ui-theme" data-theme="light" rel="stylesheet" type="text/css" href="/ui-theme-light.css">
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## Bulma
|
||||
|
||||
See Bulma element: https://bulma.io/documentation/elements/button
|
||||
@@ -22,10 +22,4 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
stories: ["../src/**/*.stories.@(ts|tsx)"],
|
||||
framework: "@storybook/react",
|
||||
core: {
|
||||
builder: "webpack5",
|
||||
},
|
||||
};
|
||||
export { Icon, Button, LinkButton, ExternalLinkButton, ExternalLink, ButtonVariants } from "@scm-manager/ui-core";
|
||||
@@ -2,77 +2,14 @@
|
||||
"name": "@scm-manager/ui-buttons",
|
||||
"version": "3.0.0-SNAPSHOT",
|
||||
"private": false,
|
||||
"main": "build/index.js",
|
||||
"module": "build/index.mjs",
|
||||
"types": "build/index.d.ts",
|
||||
"files": [
|
||||
"build"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup ./src/index.ts -d build --format esm,cjs --dts",
|
||||
"dev": "tsup ./src/index.ts -d build --format esm,cjs --dts --watch",
|
||||
"lint": "eslint src",
|
||||
"typecheck": "tsc",
|
||||
"storybook": "start-storybook -p 6006 -s ../ui-webapp/public",
|
||||
"build-storybook": "build-storybook",
|
||||
"image-snapshots": "jest \"image-snapshot.test.ts\"",
|
||||
"a11y-check": "jest \"a11y.test.ts\"",
|
||||
"depcheck": "depcheck"
|
||||
},
|
||||
"main": "index.ts",
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-router-dom": "^5.3.1",
|
||||
"classnames": "^2.2.6",
|
||||
"@scm-manager/ui-components": "3.0.0-SNAPSHOT"
|
||||
"@scm-manager/ui-core": "3.0.0-SNAPSHOT"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
"@scm-manager/ui-api": "3.0.0-SNAPSHOT",
|
||||
"@scm-manager/eslint-config": "^2.17.0",
|
||||
"@babel/core": "^7.17.8",
|
||||
"@scm-manager/tsconfig": "^2.12.0",
|
||||
"@storybook/addon-essentials": "^6.4.20",
|
||||
"@storybook/addon-interactions": "^6.4.20",
|
||||
"@storybook/addon-a11y": "^6.4.20",
|
||||
"@storybook/addon-links": "^6.4.20",
|
||||
"@storybook/builder-webpack5": "^6.4.20",
|
||||
"@storybook/manager-webpack5": "^6.4.20",
|
||||
"@storybook/react": "^6.4.20",
|
||||
"@storybook/addon-storyshots-puppeteer": "^6.4.20",
|
||||
"@storybook/addon-storyshots": "^6.4.20",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"jest-transform-css": "^4.0.1",
|
||||
"puppeteer": "^15.5.0",
|
||||
"storybook-addon-pseudo-states": "^1.15.1",
|
||||
"storybook-react-router": "^1.0.8",
|
||||
"@types/storybook-react-router": "^1.0.2",
|
||||
"sass-loader": "^12.3.0",
|
||||
"storybook-addon-themes": "^6.1.0",
|
||||
"babel-loader": "^8.2.4",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"webpack": "5",
|
||||
"tsup": "^6.1.2",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"react-query": "^3.25.1",
|
||||
"i18next": "^19.9.2",
|
||||
"react-i18next": "11",
|
||||
"i18next-fetch-backend": "^2.3.1",
|
||||
"depcheck": "^1.4.3"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@scm-manager/babel-preset"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.[tj]sx?$": "babel-jest",
|
||||
"^.+\\.(css|less|scss)$": "jest-transform-css",
|
||||
"^.+\\.mdx?$": "@storybook/addon-docs/jest-transform-mdx"
|
||||
}
|
||||
"@scm-manager/tsconfig": "^2.13.0"
|
||||
},
|
||||
"prettier": "@scm-manager/prettier-config",
|
||||
"eslintConfig": {
|
||||
|
||||
@@ -30,6 +30,10 @@ type Props = Omit<ComponentProps<typeof Notification>, "type" | "role"> & {
|
||||
error: BackendError;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
const BackendErrorNotification: FC<Props> = ({ error, ...props }) => {
|
||||
const [t] = useTranslation("plugins");
|
||||
|
||||
|
||||
@@ -50,6 +50,9 @@ const BasicErrorMessage: FC<Omit<ComponentProps<typeof Notification>, "type" | "
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
const ErrorNotification: FC<Props> = ({ error, ...props }) => {
|
||||
const [t] = useTranslation("commons");
|
||||
if (error) {
|
||||
|
||||
@@ -31,6 +31,9 @@ type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
class Image extends React.Component<Props> {
|
||||
createImageSrc = () => {
|
||||
const { src } = this.props;
|
||||
|
||||
@@ -40,6 +40,10 @@ const FixedSizedImage = styled(Image)`
|
||||
height: 128px;
|
||||
`;
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
class Loading extends React.Component<Props> {
|
||||
render() {
|
||||
const { message, t } = this.props;
|
||||
|
||||
@@ -34,6 +34,10 @@ type Props = {
|
||||
role?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
const Notification: FC<Props> = ({ type = "info", onClose, className, children, role }) => {
|
||||
const renderCloseButton = () => {
|
||||
if (onClose) {
|
||||
|
||||
@@ -71110,7 +71110,7 @@ exports[`Storyshots Repositories/RepositoryEntry Archived 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71238,7 +71238,7 @@ exports[`Storyshots Repositories/RepositoryEntry Avatar EP 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71354,7 +71354,7 @@ exports[`Storyshots Repositories/RepositoryEntry Before Title EP 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71473,7 +71473,7 @@ exports[`Storyshots Repositories/RepositoryEntry Default 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71589,7 +71589,7 @@ exports[`Storyshots Repositories/RepositoryEntry Exporting 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71717,7 +71717,7 @@ exports[`Storyshots Repositories/RepositoryEntry HealthCheck Failure 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71846,7 +71846,7 @@ exports[`Storyshots Repositories/RepositoryEntry MultiRepositoryTags 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -71986,7 +71986,7 @@ exports[`Storyshots Repositories/RepositoryEntry RepositoryFlag EP 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
@@ -72115,7 +72115,7 @@ exports[`Storyshots Repositories/RepositoryEntry With long texts 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="sc-iBkjds idsAPT is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
className="Card__RowsContainer-sc-16vnzfd-0 rKDzD is-flex is-flex-direction-column is-justify-content-center is-flex-grow-1 is-overflow-hidden is-overflow-wrap-anywhere"
|
||||
style={
|
||||
Object {
|
||||
"gap": "0.25rem",
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
// @ts-ignore scmStage is set on the index page
|
||||
export const isDevBuild = () => (window.scmStage || "").toUpperCase() !== "PRODUCTION";
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
export const createAttributesForTesting = (testId?: string) => {
|
||||
if (!testId) {
|
||||
return undefined;
|
||||
|
||||
@@ -31,6 +31,10 @@ type Props = {
|
||||
right?: ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
export default class Level extends React.Component<Props> {
|
||||
render() {
|
||||
const { className, left, children, right } = this.props;
|
||||
|
||||
@@ -28,6 +28,10 @@ type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
class SubSubtitle extends React.Component<Props> {
|
||||
render() {
|
||||
const { className, children } = this.props;
|
||||
|
||||
@@ -29,6 +29,10 @@ type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
const Subtitle: FC<Props> = ({ subtitle, className, children }) => {
|
||||
if (subtitle) {
|
||||
return <h2 className={classNames("subtitle", className)}>{subtitle}</h2>;
|
||||
|
||||
@@ -31,6 +31,10 @@ type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
|
||||
const Title: FC<Props> = ({ title, preventRefreshingPageTitle, customPageTitle, className, children }) => {
|
||||
useEffect(() => {
|
||||
if (!preventRefreshingPageTitle) {
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import { useMemo } from "react";
|
||||
|
||||
let counter = 0;
|
||||
import { useAriaId } from "@scm-manager/ui-core";
|
||||
|
||||
/**
|
||||
* @deprecated Please import the identical module from "@scm-manager/ui-core"
|
||||
*/
|
||||
export default function useGeneratedId(fallback?: string) {
|
||||
return useMemo(() => fallback ?? `scm-id-${++counter}`, [fallback]);
|
||||
return useAriaId(fallback);
|
||||
}
|
||||
|
||||
3
scm-ui/ui-core/.storybook/.babelrc
Normal file
3
scm-ui/ui-core/.storybook/.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@scm-manager/babel-preset"]
|
||||
}
|
||||
@@ -30,6 +30,7 @@ const ReactDOM = require("react-dom");
|
||||
|
||||
const root = path.resolve("..");
|
||||
|
||||
|
||||
const themedir = path.join(root, "ui-styles", "src");
|
||||
|
||||
ReactDOM.createPortal = (node) => node;
|
||||
@@ -23,4 +23,3 @@
|
||||
-->
|
||||
|
||||
<link id="ui-theme" data-theme="light" rel="stylesheet" type="text/css" href="/ui-theme-light.css">
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { ApiProvider } from "@scm-manager/ui-api";
|
||||
|
||||
81
scm-ui/ui-core/package.json
Normal file
81
scm-ui/ui-core/package.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "@scm-manager/ui-core",
|
||||
"version": "3.0.0-SNAPSHOT",
|
||||
"main": "./src/index.ts",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-router-dom": "^5.3.1",
|
||||
"classnames": "^2.3.1",
|
||||
"react-hook-form": "7",
|
||||
"react-i18next": "11",
|
||||
"react-query": "3",
|
||||
"styled-components": "5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.7.15",
|
||||
"@radix-ui/react-radio-group": "^1.1.3",
|
||||
"@radix-ui/react-slot": "^1.0.1",
|
||||
"@radix-ui/react-visually-hidden": "^1.0.3",
|
||||
"@radix-ui/react-dialog": "1.0.4",
|
||||
"@radix-ui/react-dropdown-menu": "2.0.5",
|
||||
"@radix-ui/react-popover": "1.0.6",
|
||||
"@radix-ui/react-tooltip": "1.0.2",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"mousetrap": "1.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
"@scm-manager/eslint-config": "^2.17.0",
|
||||
"@scm-manager/tsconfig": "^2.12.0",
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@types/mousetrap": "1.6.5",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/react": "12.1.5",
|
||||
"@storybook/addon-actions": "^6.5.10",
|
||||
"@storybook/addon-docs": "^6.5.14",
|
||||
"@storybook/addon-essentials": "^6.5.10",
|
||||
"@storybook/addon-interactions": "^6.5.10",
|
||||
"@storybook/addon-links": "^6.5.10",
|
||||
"@storybook/addon-a11y": "^6.5.10",
|
||||
"storybook-addon-i18next": "^1.3.0",
|
||||
"storybook-addon-pseudo-states": "^1.15.1",
|
||||
"@storybook/builder-webpack5": "^6.5.10",
|
||||
"@storybook/manager-webpack5": "^6.5.10",
|
||||
"@storybook/react": "^6.5.10",
|
||||
"@storybook/testing-library": "^0.0.13",
|
||||
"@storybook/addon-storyshots-puppeteer": "^6.4.20",
|
||||
"@storybook/addon-storyshots": "^6.4.20",
|
||||
"storybook-addon-mock": "^3.2.0",
|
||||
"storybook-addon-themes": "^6.1.0",
|
||||
"storybook-react-router": "^1.0.8",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"webpack": "5",
|
||||
"@babel/core": "^7.19.0",
|
||||
"i18next": "^19.9.2",
|
||||
"react-i18next": "11",
|
||||
"i18next-fetch-backend": "^2.3.1",
|
||||
"babel-loader": "^8.2.5",
|
||||
"depcheck": "^1.4.3",
|
||||
"jest-extended": "3.1.0"
|
||||
},
|
||||
"prettier": "@scm-manager/prettier-config",
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"jest": {
|
||||
"setupFilesAfterEnv": [
|
||||
"jest-extended/all"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from "react";
|
||||
import { Link as ReactRouterLink, LinkProps as ReactRouterLinkProps } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../helpers";
|
||||
|
||||
/**
|
||||
* @beta
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Meta } from "@storybook/addon-docs";
|
||||
import { Button } from "../";
|
||||
|
||||
<Meta title="Introduction"/>
|
||||
|
||||
# Buttons
|
||||
|
||||
The `@scm-manager/ui-core` library provides [atoms](https://atomicdesign.bradfrost.com/chapter-2/#atoms) implemented
|
||||
as minimal wrappers around native html elements styled to match the general SCM-Manager aesthetic.
|
||||
|
||||
## Components
|
||||
|
||||
There are three actionable components available. Styling is consistent amongst them and all have the required `variant` property.
|
||||
|
||||
1. [Button](?path=/story/components--button)
|
||||
2. [Link Button](?path=/story/components--link-button)
|
||||
3. [External Link Button](?path=/story/components--external-link-button)
|
||||
|
||||
## Usage
|
||||
|
||||
Actionable components serve a dedicated purpose. It is therefore important to know when and how to use them.
|
||||
|
||||
### Variants
|
||||
|
||||
There are four variants available to each of the three button types, varying in importance.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Emphasis</th>
|
||||
<th>Button Variant</th>
|
||||
<th>Usage Examples</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Very High</td>
|
||||
<td><Button variant="signal">Signal</Button></td>
|
||||
<td>Destructive actions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>High</td>
|
||||
<td><Button variant="primary">Primary</Button></td>
|
||||
<td>Form submit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Normal</td>
|
||||
<td><Button variant="secondary">Secondary</Button></td>
|
||||
<td>Cancel action in dialog</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Low</td>
|
||||
<td><Button variant="tertiary">Tertiary</Button></td>
|
||||
<td>Circumstantially relevant action on page with many actionable elements</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Content
|
||||
|
||||
Buttons exclusively contain text and no icons. Icons tend to be ambiguous and not always applicable which leads to inconsistent
|
||||
and cluttered layouts.
|
||||
|
||||
Button text should be short, concise and describe the action performed.
|
||||
22
scm-ui/ui-core/src/base/buttons/docs/usage.stories.mdx
Normal file
22
scm-ui/ui-core/src/base/buttons/docs/usage.stories.mdx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Meta, Story } from "@storybook/addon-docs";
|
||||
import { Button } from "../";
|
||||
|
||||
<Meta title="Usage" parameters={{
|
||||
storyshots: { disable: true }
|
||||
}} />
|
||||
|
||||
In confirmation dialogs, there are two actions.<br/>
|
||||
One to cancel the current process and one to confirm it.<br/>
|
||||
Aborting is always the secondary action, confirmation always the primary.
|
||||
Focus is always on the cancelling action.
|
||||
|
||||
<Story name="Confirmation Dialog">
|
||||
<div>
|
||||
<h4>Delete User</h4>
|
||||
<p>Do you really want to delete this user ?</p>
|
||||
<div>
|
||||
<Button variant="secondary">Cancel</Button>
|
||||
<Button variant="primary">Delete</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
@@ -26,7 +26,7 @@ import React, { useCallback, useEffect } from "react";
|
||||
import { ScmFormPathContextProvider, useScmFormPathContext } from "./FormPathContext";
|
||||
import { ScmFormContextProvider, useScmFormContext } from "./ScmFormContext";
|
||||
import { DeepPartial, UseFieldArrayReturn, useForm, UseFormReturn } from "react-hook-form";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { Button } from "../buttons";
|
||||
import { prefixWithoutIndices } from "./helpers";
|
||||
import { useScmFormListContext } from "./ScmFormListContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
import { useConfigLink } from "@scm-manager/ui-api";
|
||||
import { Loading } from "@scm-manager/ui-components";
|
||||
import { Loading } from "../misc";
|
||||
import React, { ComponentProps } from "react";
|
||||
import { HalRepresentation } from "@scm-manager/ui-types";
|
||||
import Form from "./Form";
|
||||
@@ -24,10 +24,11 @@
|
||||
|
||||
import React, { FC, useCallback, useEffect, useState } from "react";
|
||||
import { DeepPartial, SubmitHandler, useForm, UseFormReturn } from "react-hook-form";
|
||||
import { ErrorNotification, Level } from "@scm-manager/ui-components";
|
||||
import { ErrorNotification } from "../notifications";
|
||||
import { Level } from "../misc";
|
||||
import { ScmFormContextProvider } from "./ScmFormContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { Button } from "../buttons";
|
||||
import styled from "styled-components";
|
||||
import { setValues } from "./helpers";
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Tooltip } from "@scm-manager/ui-overlays";
|
||||
import { Tooltip } from "../../../overlays";
|
||||
|
||||
type Props = { text?: string; className?: string };
|
||||
const Help = ({ text, className }: Props) => (
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
import React, { InputHTMLAttributes } from "react";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../../helpers";
|
||||
import Help from "../base/help/Help";
|
||||
import styled from "styled-components";
|
||||
import classNames from "classnames";
|
||||
@@ -22,8 +22,8 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { KeyboardEventHandler, PropsWithRef, ReactElement, Ref, RefObject, useCallback } from "react";
|
||||
import { createAttributesForTesting, useGeneratedId } from "@scm-manager/ui-components";
|
||||
import React, { KeyboardEventHandler, PropsWithRef, ReactElement, Ref, useCallback } from "react";
|
||||
import { createAttributesForTesting, useAriaId } from "../../helpers";
|
||||
import Field from "../base/Field";
|
||||
import Label from "../base/label/Label";
|
||||
import Help from "../base/help/Help";
|
||||
@@ -114,9 +114,9 @@ const ChipInputField = function ChipInputField<T>(
|
||||
(item) => (createDeleteText ? createDeleteText(item) : t("delete", { item })),
|
||||
[createDeleteText, t]
|
||||
);
|
||||
const inputId = useGeneratedId(id ?? testId);
|
||||
const labelId = useGeneratedId();
|
||||
const inputDescriptionId = useGeneratedId();
|
||||
const inputId = useAriaId(id ?? testId);
|
||||
const labelId = useAriaId();
|
||||
const inputDescriptionId = useAriaId();
|
||||
const variant = error ? "danger" : undefined;
|
||||
return (
|
||||
<Field className={className} aria-owns={inputId}>
|
||||
@@ -36,7 +36,7 @@ import { Combobox as HeadlessCombobox } from "@headlessui/react";
|
||||
import classNames from "classnames";
|
||||
import styled from "styled-components";
|
||||
import { withForwardRef } from "../helpers";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../../helpers";
|
||||
import { Option } from "@scm-manager/ui-types";
|
||||
|
||||
const OptionsWrapper = styled(HeadlessCombobox.Options).attrs({
|
||||
@@ -26,7 +26,7 @@ import Field from "../base/Field";
|
||||
import Label from "../base/label/Label";
|
||||
import Help from "../base/help/Help";
|
||||
import React from "react";
|
||||
import { useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { useAriaId } from "../../helpers";
|
||||
import { withForwardRef } from "../helpers";
|
||||
import Combobox, { ComboboxProps } from "./Combobox";
|
||||
import classNames from "classnames";
|
||||
@@ -46,7 +46,7 @@ const ComboboxField = function ComboboxField<T>(
|
||||
}: ComboboxProps<T> & { label: string; helpText?: string; error?: string; isLoading?: boolean },
|
||||
ref: React.ForwardedRef<HTMLInputElement>
|
||||
) {
|
||||
const labelId = useGeneratedId();
|
||||
const labelId = useAriaId();
|
||||
return (
|
||||
<Field className={className}>
|
||||
<Label id={labelId}>
|
||||
@@ -41,7 +41,7 @@ import React, {
|
||||
import { Slot } from "@radix-ui/react-slot";
|
||||
import { Option } from "@scm-manager/ui-types";
|
||||
import { mergeRefs, withForwardRef } from "../helpers";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { Button } from "../../buttons";
|
||||
|
||||
type ChipInputContextType<T> = {
|
||||
add(newValue: Option<T>): void;
|
||||
@@ -25,7 +25,7 @@
|
||||
import React, { InputHTMLAttributes } from "react";
|
||||
import classNames from "classnames";
|
||||
import { createVariantClass, Variant } from "../variants";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../../helpers";
|
||||
|
||||
type Props = {
|
||||
variant?: Variant;
|
||||
@@ -29,7 +29,7 @@ import Label from "../base/label/Label";
|
||||
import FieldMessage from "../base/field-message/FieldMessage";
|
||||
import Input from "./Input";
|
||||
import Help from "../base/help/Help";
|
||||
import { useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { useAriaId } from "../../helpers";
|
||||
|
||||
type InputFieldProps = {
|
||||
label: string;
|
||||
@@ -42,7 +42,7 @@ type InputFieldProps = {
|
||||
*/
|
||||
const InputField = React.forwardRef<HTMLInputElement, InputFieldProps>(
|
||||
({ label, helpText, error, className, id, ...props }, ref) => {
|
||||
const inputId = useGeneratedId(id ?? props.testId);
|
||||
const inputId = useAriaId(id ?? props.testId);
|
||||
const variant = error ? "danger" : undefined;
|
||||
return (
|
||||
<Field className={className}>
|
||||
@@ -25,7 +25,7 @@
|
||||
import React, { InputHTMLAttributes } from "react";
|
||||
import classNames from "classnames";
|
||||
import { createVariantClass, Variant } from "../variants";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../../helpers";
|
||||
|
||||
type Props = {
|
||||
variant?: Variant;
|
||||
@@ -26,10 +26,10 @@ import React from "react";
|
||||
import { Path, PathValue } from "react-hook-form";
|
||||
import { useScmFormContext } from "../ScmFormContext";
|
||||
import { ScmFormPathContextProvider, useScmFormPathContext } from "../FormPathContext";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { prefixWithoutIndices } from "../helpers";
|
||||
import { useScmFormListContext } from "../ScmFormListContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "../../buttons";
|
||||
|
||||
type ArrayItemType<T> = T extends Array<infer U> ? U : unknown;
|
||||
|
||||
@@ -26,7 +26,7 @@ import React, { ComponentProps } from "react";
|
||||
import classNames from "classnames";
|
||||
import Help from "../base/help/Help";
|
||||
import * as RadioGroup from "@radix-ui/react-radio-group";
|
||||
import { createAttributesForTesting, useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting, useAriaId } from "../../helpers";
|
||||
import styled from "styled-components";
|
||||
import { useRadioButtonContext } from "./RadioButtonContext";
|
||||
|
||||
@@ -90,7 +90,7 @@ type Props = {
|
||||
const RadioButton = React.forwardRef<HTMLButtonElement, Props>(
|
||||
({ id, testId, indicatorClassName, label, labelClassName, className, helpText, value, ...props }, ref) => {
|
||||
const context = useRadioButtonContext();
|
||||
const inputId = useGeneratedId(id);
|
||||
const inputId = useAriaId(id);
|
||||
const labelKey = `${context?.prefix}.radio.${value}`;
|
||||
|
||||
return (
|
||||
@@ -25,7 +25,7 @@
|
||||
import React, { InputHTMLAttributes, Key, OptionHTMLAttributes } from "react";
|
||||
import classNames from "classnames";
|
||||
import { createVariantClass, Variant } from "../variants";
|
||||
import { createAttributesForTesting } from "@scm-manager/ui-components";
|
||||
import { createAttributesForTesting } from "../../helpers";
|
||||
|
||||
type Props = {
|
||||
variant?: Variant;
|
||||
@@ -29,7 +29,7 @@ import Label from "../base/label/Label";
|
||||
import FieldMessage from "../base/field-message/FieldMessage";
|
||||
import Help from "../base/help/Help";
|
||||
import Select from "./Select";
|
||||
import { useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { useAriaId } from "../../helpers";
|
||||
|
||||
type Props = {
|
||||
label: string;
|
||||
@@ -44,7 +44,7 @@ type Props = {
|
||||
*/
|
||||
const SelectField = React.forwardRef<HTMLSelectElement, Props>(
|
||||
({ label, helpText, error, className, id, ...props }, ref) => {
|
||||
const selectId = useGeneratedId(id ?? props.testId);
|
||||
const selectId = useAriaId(id ?? props.testId);
|
||||
const variant = error ? "danger" : undefined;
|
||||
return (
|
||||
<Field className={className}>
|
||||
@@ -26,12 +26,12 @@ import React, { ReactElement } from "react";
|
||||
import { Path, PathValue } from "react-hook-form";
|
||||
import { useScmFormContext } from "../ScmFormContext";
|
||||
import { ScmFormPathContextProvider, useScmFormPathContext } from "../FormPathContext";
|
||||
import { Button } from "@scm-manager/ui-buttons";
|
||||
import { Button } from "../../buttons";
|
||||
import { prefixWithoutIndices } from "../helpers";
|
||||
import classNames from "classnames";
|
||||
import { useScmFormListContext } from "../ScmFormListContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Notification } from "@scm-manager/ui-components";
|
||||
import { Notification } from "../../notifications";
|
||||
|
||||
type RenderProps<T extends Record<string, unknown>, PATH extends Path<T>> = {
|
||||
value: PathValue<T, PATH>;
|
||||
@@ -22,46 +22,23 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import i18n from "i18next";
|
||||
import { withThemes } from "storybook-addon-themes";
|
||||
export const isDevBuild = () =>
|
||||
((window as unknown as { scmStage: string }).scmStage || "").toUpperCase() !== "PRODUCTION";
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
whitelist: ["en", "de"],
|
||||
lng: "en",
|
||||
fallbackLng: "en",
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
const Decorator = ({ children, themeName }) => {
|
||||
useEffect(() => {
|
||||
const link = document.querySelector("#ui-theme");
|
||||
if (link && link["data-theme"] !== themeName) {
|
||||
link.href = `ui-theme-${themeName}.css`;
|
||||
link["data-theme"] = themeName;
|
||||
export const createAttributesForTesting = (testId?: string) => {
|
||||
if (!testId) {
|
||||
return undefined;
|
||||
}
|
||||
}, [themeName]);
|
||||
return <>{children}</>;
|
||||
return {
|
||||
"data-testid": normalizeTestId(testId),
|
||||
};
|
||||
};
|
||||
|
||||
export const decorators = [withThemes];
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
themes: {
|
||||
Decorator,
|
||||
clearable: false,
|
||||
default: "light",
|
||||
list: [
|
||||
{ name: "light", color: "#fff" },
|
||||
{ name: "highcontrast", color: "#050514" },
|
||||
{ name: "dark", color: "#121212" },
|
||||
],
|
||||
},
|
||||
// keep this weird function instead of replaceAll because of browser compatibility
|
||||
const normalizeTestId = (testId?: string) => {
|
||||
let id = testId?.toLowerCase();
|
||||
while (id?.includes(" ")) {
|
||||
id = id.replace(" ", "-");
|
||||
}
|
||||
return id;
|
||||
};
|
||||
@@ -22,15 +22,5 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
storySort: (a, b) => (a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, { numeric: true })),
|
||||
},
|
||||
};
|
||||
export { default as useAriaId } from "./useAriaId";
|
||||
export { createAttributesForTesting, isDevBuild } from "./devbuild";
|
||||
31
scm-ui/ui-core/src/base/helpers/useAriaId.tsx
Normal file
31
scm-ui/ui-core/src/base/helpers/useAriaId.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import { useMemo } from "react";
|
||||
|
||||
let counter = 0;
|
||||
|
||||
export default function useAriaId(id?: string) {
|
||||
return useMemo(() => id ?? `scm-id-${++counter}`, [id]);
|
||||
}
|
||||
34
scm-ui/ui-core/src/base/index.ts
Normal file
34
scm-ui/ui-core/src/base/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
export * from "./buttons"
|
||||
export * from "./forms"
|
||||
export * from "./helpers"
|
||||
export * from "./misc"
|
||||
export * from "./layout"
|
||||
export * from "./notifications"
|
||||
export * from "./overlays"
|
||||
export * from "./shortcuts"
|
||||
export * from "./text"
|
||||
|
||||
@@ -28,8 +28,8 @@ import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import CardList, { CardListBox, CardListCard } from "./CardList";
|
||||
import CardTitle from "../card/CardTitle";
|
||||
import { Menu } from "@scm-manager/ui-overlays";
|
||||
import { Icon } from "@scm-manager/ui-buttons";
|
||||
import { Menu } from "../../overlays";
|
||||
import { Icon } from "../../buttons";
|
||||
import CardRow, { SecondaryRow } from "../card/CardRow";
|
||||
import { CardDetail, CardDetailLabel, CardDetails, CardDetailTag, CardLinkDetail } from "../card/CardDetail";
|
||||
|
||||
@@ -38,8 +38,8 @@ import {
|
||||
CardLinkDetail,
|
||||
} from "./CardDetail";
|
||||
import Card from "./Card";
|
||||
import { Popover } from "@scm-manager/ui-overlays";
|
||||
import { Icon } from "@scm-manager/ui-buttons";
|
||||
import { Popover } from "../../overlays";
|
||||
import { Icon } from "../../buttons";
|
||||
|
||||
export default {
|
||||
title: "Card",
|
||||
@@ -30,10 +30,10 @@ import React, {
|
||||
ReactNode,
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import { useGeneratedId } from "@scm-manager/ui-components";
|
||||
import { useAriaId } from "../../helpers";
|
||||
import styled from "styled-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Icon } from "@scm-manager/ui-buttons";
|
||||
import { Icon } from "../../buttons";
|
||||
|
||||
export const CardVariants = {
|
||||
LIGHT: "light",
|
||||
@@ -62,7 +62,7 @@ type CardVariantProps = {
|
||||
*/
|
||||
export const CardDetail = React.forwardRef<HTMLSpanElement, CardDetailProps>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
const labelId = useGeneratedId();
|
||||
const labelId = useAriaId();
|
||||
return (
|
||||
<span {...props} className={classNames("is-flex is-align-items-center has-gap-1 p-1", className)} ref={ref}>
|
||||
{typeof children === "function" ? children({ labelId }) : children}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user