diff --git a/PLIPs.md b/PLIPs.md new file mode 100644 index 0000000000..669bdccfb1 --- /dev/null +++ b/PLIPs.md @@ -0,0 +1,8 @@ +# Plone Improvement Proposals (PLIPs) + +For details of the PLIP process, read the following. + +- [Plone Improvement Proposals (PLIPs)](https://6.docs.plone.org/contributing/core/plips.html) +- [PLIP review](https://6.docs.plone.org/contributing/core/plip-review.html) + +You can also [browse the current list of open PLIPs for Volto](https://github.com/plone/volto/labels/03%20type%3A%20feature%20(plip)). diff --git a/packages/cmsui/.eslintrc.cjs b/packages/cmsui/.eslintrc.cjs new file mode 100644 index 0000000000..b3a71fc44c --- /dev/null +++ b/packages/cmsui/.eslintrc.cjs @@ -0,0 +1,11 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + overrides: [ + { + files: ['**/*.ts', '**/*.tsx'], + extends: [ + 'plugin:react/jsx-runtime', // We only want this for non-library code (eg. volto add-ons) + ], + }, + ], +}; diff --git a/packages/cmsui/.release-it.json b/packages/cmsui/.release-it.json new file mode 100644 index 0000000000..507f953edc --- /dev/null +++ b/packages/cmsui/.release-it.json @@ -0,0 +1,29 @@ +{ + "plugins": { + "../scripts/prepublish.js": {} + }, + "hooks": { + "after:bump": [ + "pipx run towncrier build --draft --yes --version ${version} > .changelog.draft", + "pipx run towncrier build --yes --version ${version}" + ], + "after:release": "rm .changelog.draft" + }, + "npm": { + "publish": false + }, + "git": { + "commitArgs": ["--no-verify"], + "changelog": "pipx run towncrier build --draft --yes --version 0.0.0", + "requireUpstream": false, + "requireCleanWorkingDir": false, + "commitMessage": "Release @plone/cmsui ${version}", + "tagName": "plone-cmsui-${version}", + "tagAnnotation": "Release @plone/cmsui ${version}" + }, + "github": { + "release": true, + "releaseName": "@plone/cmsui ${version}", + "releaseNotes": "cat .changelog.draft" + } +} diff --git a/packages/cmsui/.storybook/Logo.svg b/packages/cmsui/.storybook/Logo.svg new file mode 100644 index 0000000000..5a7ba56902 --- /dev/null +++ b/packages/cmsui/.storybook/Logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/cmsui/.storybook/main.ts b/packages/cmsui/.storybook/main.ts new file mode 100644 index 0000000000..cf9f4ddec3 --- /dev/null +++ b/packages/cmsui/.storybook/main.ts @@ -0,0 +1,41 @@ +import type { StorybookConfig } from '@storybook/react-vite'; +import { mergeConfig } from 'vite'; + +const config: StorybookConfig = { + // For some reason the property does not allow negation + // https://github.com/storybookjs/storybook/issues/11181#issuecomment-1535288804 + stories: [ + '../components/**/*.mdx', + '../components/**/*.stories.@(js|jsx|ts|tsx)', + ], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/react-vite', + options: {}, + }, + docs: { + autodocs: 'tag', + }, + typescript: { + reactDocgen: 'react-docgen-typescript', + reactDocgenTypescriptOptions: { + compilerOptions: { + allowSyntheticDefaultImports: false, + esModuleInterop: false, + }, + propFilter: () => true, + }, + }, + async viteFinal(config) { + return mergeConfig(config, { + build: { + minify: false, + }, + }); + }, +}; +export default config; diff --git a/packages/cmsui/.storybook/manager.js b/packages/cmsui/.storybook/manager.js new file mode 100644 index 0000000000..2e62084432 --- /dev/null +++ b/packages/cmsui/.storybook/manager.js @@ -0,0 +1,6 @@ +import { addons } from '@storybook/manager-api'; +import theme from './theme'; + +addons.setConfig({ + theme, +}); diff --git a/packages/cmsui/.storybook/preview-head.html b/packages/cmsui/.storybook/preview-head.html new file mode 100644 index 0000000000..05da1e9dfb --- /dev/null +++ b/packages/cmsui/.storybook/preview-head.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/cmsui/.storybook/preview.ts b/packages/cmsui/.storybook/preview.ts new file mode 100644 index 0000000000..362843c9bc --- /dev/null +++ b/packages/cmsui/.storybook/preview.ts @@ -0,0 +1,24 @@ +import './storybook-base.css'; +import '@plone/components/dist/basic.css'; +import '../main.css'; +import config from '@plone/registry'; +import installSlots from '../config'; +import installBlocks from '@plone/blocks'; + +config.set('slots', {}); +config.set('utilities', {}); +installSlots(config); +installBlocks(config); + +export const parameters = { + backgrounds: { + default: 'light', + }, + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; diff --git a/packages/cmsui/.storybook/storybook-base.css b/packages/cmsui/.storybook/storybook-base.css new file mode 100644 index 0000000000..f55ba4bf27 --- /dev/null +++ b/packages/cmsui/.storybook/storybook-base.css @@ -0,0 +1,19 @@ +/* Base styles */ +:root { + --basic-font-family: system-ui; + --basic-font-size: 16px; + background: var(--background-color); + font-family: var(--basic-font-family); + font-size: var(--basic-font-size); + line-height: 1.5; +} + +.sbdocs.sbdocs-content { + p { + font-size: 16px; + } +} + +#storybook-root { + width: 100vw; +} diff --git a/packages/cmsui/.storybook/theme.ts b/packages/cmsui/.storybook/theme.ts new file mode 100644 index 0000000000..3262e1f700 --- /dev/null +++ b/packages/cmsui/.storybook/theme.ts @@ -0,0 +1,10 @@ +import { create } from '@storybook/theming/create'; +import logo from './Logo.svg'; + +export default create({ + base: 'light', + brandTitle: '@plone/components StoryBook', + brandUrl: 'https://plone-components.netlify.app/', + brandImage: logo, + brandTarget: '_self', +}); diff --git a/packages/cmsui/.stylelintrc b/packages/cmsui/.stylelintrc new file mode 100644 index 0000000000..8ac62f8d0f --- /dev/null +++ b/packages/cmsui/.stylelintrc @@ -0,0 +1,14 @@ +{ + "extends": ["stylelint-config-idiomatic-order"], + "plugins": ["stylelint-prettier"], + "overrides": [ + { + "files": ["**/*.scss"], + "customSyntax": "postcss-scss" + } + ], + "rules": { + "prettier/prettier": true, + "order/properties-alphabetical-order": null + } +} diff --git a/packages/cmsui/CHANGELOG.md b/packages/cmsui/CHANGELOG.md new file mode 100644 index 0000000000..2969638257 --- /dev/null +++ b/packages/cmsui/CHANGELOG.md @@ -0,0 +1,11 @@ +# @plone/cmsui Release Notes + + + + + +## 1.0.0 (unreleased) diff --git a/packages/cmsui/README.md b/packages/cmsui/README.md new file mode 100644 index 0000000000..ee5d757cd6 --- /dev/null +++ b/packages/cmsui/README.md @@ -0,0 +1,8 @@ +# `@plone/cmsui` + +This package provides default structural slots for Plone 7 and the API-first story. + +> [!WARNING] +> This package or app is experimental. +> The community offers no support whatsoever for it. +> Breaking changes may occur without notice. diff --git a/packages/cmsui/index.ts b/packages/cmsui/index.ts new file mode 100644 index 0000000000..7258290153 --- /dev/null +++ b/packages/cmsui/index.ts @@ -0,0 +1,5 @@ +import type { ConfigType } from '@plone/registry'; + +export default function install(config: ConfigType) { + return config; +} diff --git a/packages/cmsui/main.css b/packages/cmsui/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cmsui/news/.gitkeep b/packages/cmsui/news/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cmsui/package.json b/packages/cmsui/package.json new file mode 100644 index 0000000000..28597732df --- /dev/null +++ b/packages/cmsui/package.json @@ -0,0 +1,79 @@ +{ + "name": "@plone/cmsui", + "description": "Plone CMSUI components", + "maintainers": [ + { + "name": "Plone Foundation", + "url": "https://plone.org" + } + ], + "funding": "https://github.com/sponsors/plone", + "license": "MIT", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/plone/volto.git" + }, + "bugs": { + "url": "https://github.com/plone/volto/issues" + }, + "homepage": "https://plone.org", + "keywords": [ + "volto", + "plone", + "plone6", + "react", + "helpers" + ], + "publishConfig": { + "access": "public" + }, + "main": "index.ts", + "scripts": { + "test": "vitest", + "dry-release": "release-it --dry-run", + "release": "release-it", + "release-major-alpha": "release-it major --preRelease=alpha", + "release-alpha": "release-it --preRelease=alpha", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + }, + "dependencies": { + "@plone/client": "workspace:*", + "@plone/components": "workspace:*", + "@plone/registry": "workspace:*", + "react-aria-components": "^1.5.0" + }, + "devDependencies": { + "@plone/types": "workspace:*", + "@storybook/addon-essentials": "^8.0.4", + "@storybook/addon-interactions": "^8.0.4", + "@storybook/addon-links": "^8.0.4", + "@storybook/addon-mdx-gfm": "^8.0.4", + "@storybook/blocks": "^8.0.4", + "@storybook/manager-api": "^8.0.4", + "@storybook/react": "^8.0.4", + "@storybook/react-vite": "^8.0.4", + "@storybook/theming": "^8.0.4", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint-plugin-storybook": "^0.8.0", + "jest-axe": "^8.0.0", + "release-it": "17.1.1", + "storybook": "^8.0.4", + "tsconfig": "workspace:*", + "typescript": "^5.6.3", + "vite": "^5.4.8", + "vitest": "^2.1.3", + "vitest-axe": "^0.1.0" + } +} diff --git a/packages/cmsui/setupTesting.ts b/packages/cmsui/setupTesting.ts new file mode 100644 index 0000000000..8bc87fa36e --- /dev/null +++ b/packages/cmsui/setupTesting.ts @@ -0,0 +1,3 @@ +import '@testing-library/jest-dom'; +import { toHaveNoViolations } from 'jest-axe'; +expect.extend(toHaveNoViolations); diff --git a/packages/cmsui/stories.ts b/packages/cmsui/stories.ts new file mode 100644 index 0000000000..6a668df163 --- /dev/null +++ b/packages/cmsui/stories.ts @@ -0,0 +1,22 @@ +export const storyData = { + blocks: { + '7ab29abe-b38c-406b-94d7-b270e544a998': { + '@type': 'slate', + value: [ + { + type: 'p', + children: [ + { + text: 'Lorem ipsum dolor sit amet eu tempus ornare elit. Curabitur egestas quisque molestie pellentesque nunc imperdiet posuere morbi nunc eleifend. Volutpat enim augue blandit aliquam interdum pulvinar eu mattis congue. Eleifend mauris ut fermentum egestas mi faucibus adipiscing arcu nibh scelerisque justo habitasse. Mi consectetur hac maecenas leo dictumst vitae phasellus quam praesent vivamus nullam imperdiet integer mauris.', + }, + ], + }, + ], + plaintext: + 'Lorem ipsum dolor sit amet eu tempus ornare elit. Curabitur egestas quisque molestie pellentesque nunc imperdiet posuere morbi nunc eleifend. Volutpat enim augue blandit aliquam interdum pulvinar eu mattis congue. Eleifend mauris ut fermentum egestas mi faucibus adipiscing arcu nibh scelerisque justo habitasse. Mi consectetur hac maecenas leo dictumst vitae phasellus quam praesent vivamus nullam imperdiet integer mauris.', + }, + }, + blocks_layout: { + items: ['7ab29abe-b38c-406b-94d7-b270e544a998'], + }, +}; diff --git a/packages/cmsui/towncrier.toml b/packages/cmsui/towncrier.toml new file mode 100644 index 0000000000..3ef721f378 --- /dev/null +++ b/packages/cmsui/towncrier.toml @@ -0,0 +1,33 @@ +[tool.towncrier] +filename = "CHANGELOG.md" +directory = "news/" +title_format = "## {version} ({project_date})" +underlines = ["", "", ""] +template = "../scripts/templates/towncrier_template.jinja" +start_string = "\n" +issue_format = "[#{issue}](https://github.com/plone/volto/issues/{issue})" + +[[tool.towncrier.type]] +directory = "breaking" +name = "Breaking" +showcontent = true + +[[tool.towncrier.type]] +directory = "feature" +name = "Feature" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bugfix" +showcontent = true + +[[tool.towncrier.type]] +directory = "internal" +name = "Internal" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation" +showcontent = true diff --git a/packages/cmsui/tsconfig.json b/packages/cmsui/tsconfig.json new file mode 100644 index 0000000000..2965402840 --- /dev/null +++ b/packages/cmsui/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "tsconfig/react-library.json", + "include": ["**/*.ts", "**/*.tsx"], + "exclude": [ + "node_modules", + "build", + "public", + "coverage", + "src/**/*.test.{js,jsx,ts,tsx}", + "src/**/*.spec.{js,jsx,ts,tsx}", + "src/**/*.stories.{js,jsx,ts,tsx}" + ] +} diff --git a/packages/cmsui/vitest.config.ts b/packages/cmsui/vitest.config.ts new file mode 100644 index 0000000000..fddf5f61f7 --- /dev/null +++ b/packages/cmsui/vitest.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vitest/config'; + +// https://vitejs.dev/config/ +export default defineConfig({ + test: { + globals: true, + environment: 'jsdom', + setupFiles: './setupTesting.ts', + // you might want to disable it, if you don't have tests that rely on CSS + // since parsing CSS is slow + css: true, + exclude: ['**/node_modules/**', '**/lib/**'], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae6dfec91f..3f68d68045 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -517,6 +517,91 @@ importers: specifier: ^7.2.0 version: 7.2.0(debug@4.3.4) + packages/cmsui: + dependencies: + '@plone/client': + specifier: workspace:* + version: link:../client + '@plone/components': + specifier: workspace:* + version: link:../components + '@plone/registry': + specifier: workspace:* + version: link:../registry + react: + specifier: ^16.8.0 || ^17.0.0 || ^18.0.0 + version: 18.2.0 + react-aria-components: + specifier: ^1.5.0 + version: 1.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-dom: + specifier: ^16.8.0 || ^17.0.0 || ^18.0.0 + version: 18.2.0(react@18.2.0) + devDependencies: + '@plone/types': + specifier: workspace:* + version: link:../types + '@storybook/addon-essentials': + specifier: ^8.0.4 + version: 8.0.8(@types/react@18.3.12)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@storybook/addon-interactions': + specifier: ^8.0.4 + version: 8.0.8(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@2.1.3(@types/node@20.12.7)(jsdom@22.1.0)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3)) + '@storybook/addon-links': + specifier: ^8.0.4 + version: 8.0.8(react@18.2.0) + '@storybook/addon-mdx-gfm': + specifier: ^8.0.4 + version: 8.0.8 + '@storybook/blocks': + specifier: ^8.0.4 + version: 8.0.8(@types/react@18.3.12)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@storybook/manager-api': + specifier: ^8.0.4 + version: 8.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@storybook/react': + specifier: ^8.0.4 + version: 8.0.8(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.6.3) + '@storybook/react-vite': + specifier: ^8.0.4 + version: 8.0.8(@preact/preset-vite@2.8.2(@babel/core@7.25.8)(vite@5.4.9(@types/node@20.12.7)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3)))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@4.24.0)(typescript@5.6.3)(vite@5.4.9(@types/node@20.12.7)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3)) + '@storybook/theming': + specifier: ^8.0.4 + version: 8.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@types/react': + specifier: ^18 + version: 18.3.12 + '@types/react-dom': + specifier: ^18 + version: 18.3.1 + eslint-plugin-storybook: + specifier: ^0.8.0 + version: 0.8.0(eslint@8.57.0)(typescript@5.6.3) + jest-axe: + specifier: ^8.0.0 + version: 8.0.0 + release-it: + specifier: 17.1.1 + version: 17.1.1(typescript@5.6.3) + storybook: + specifier: ^8.0.4 + version: 8.0.8(@babel/preset-env@7.24.4(@babel/core@7.25.8))(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + tsconfig: + specifier: workspace:* + version: link:../tsconfig + typescript: + specifier: ^5.6.3 + version: 5.6.3 + vite: + specifier: ^5.4.8 + version: 5.4.9(@types/node@20.12.7)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3) + vitest: + specifier: ^2.1.3 + version: 2.1.3(@types/node@20.12.7)(jsdom@22.1.0)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3) + vitest-axe: + specifier: ^0.1.0 + version: 0.1.0(vitest@2.1.3(@types/node@20.12.7)(jsdom@22.1.0)(less@3.11.1)(lightningcss@1.28.1)(sass@1.75.0)(terser@5.30.3)) + packages/components: dependencies: '@react-aria/utils': @@ -18378,9 +18463,11 @@ snapshots: '@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.25.8)': dependencies: '@babel/core': 7.25.8 - '@babel/helper-module-imports': 7.24.3 + '@babel/helper-module-imports': 7.25.7 '@babel/helper-plugin-utils': 7.25.7 '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.25.8) + transitivePeerDependencies: + - supports-color '@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.4)': dependencies: @@ -19143,11 +19230,11 @@ snapshots: '@babel/preset-env@7.24.4(@babel/core@7.25.8)': dependencies: - '@babel/compat-data': 7.24.4 + '@babel/compat-data': 7.25.8 '@babel/core': 7.25.8 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 + '@babel/helper-compilation-targets': 7.25.7 + '@babel/helper-plugin-utils': 7.25.7 + '@babel/helper-validator-option': 7.25.7 '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.4(@babel/core@7.25.8) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.25.8) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.25.8)