├── .commitlintrc ├── .git-blame-ignore-revs ├── .githooks ├── commit-msg └── pre-push ├── .github ├── ISSUE_TEMPLATE │ ├── accessibility-issue.md │ └── new-component.md └── workflows │ ├── preview.yml │ ├── publish.yml │ ├── release.yml │ └── test-and-build.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .storybook ├── .htaccess ├── main.js ├── manager.js ├── preview-head.html └── preview.js ├── .stylelintrc.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cdn-ui ├── cors.xml ├── index.html └── list.html ├── cem ├── add-dependencies-in-description.js ├── add-github-source-in-description.js ├── generate-cem-vite-plugin.js ├── identify-readonly-members.js ├── list-images.js ├── remove-private-members.js ├── sort-items.js ├── support-cc-events.js ├── support-cssdisplay-jsdoc.js ├── support-typedef-jsdoc-utils.js └── support-typedef-jsdoc.js ├── custom-elements-manifest.config.mjs ├── custom-elements.json ├── demo-smart ├── cc-pricing-page │ └── index.html ├── index.html └── index.js ├── docs ├── adr │ ├── adr-0001-why-do-we-wrap-button-clicks.md │ ├── adr-0002-how-we-do-i18n.md │ ├── adr-0003-why-a-custom-datetime-relative-component.md │ ├── adr-0004-why-wrap-input-textarea.md │ ├── adr-0005-how-should-we-implement-copy-to-clipboard.md │ ├── adr-0006-why-the-cc-overview-uses-slots.md │ ├── adr-0007-why-a-text-based-tags-input.md │ ├── adr-0008-why-an-event-called-requestimplicitsubmit.md │ ├── adr-0009-how-we-use-the-new-storybook-csf-and-docs-page.md │ ├── adr-0010-introducing-html-in-i18n-strings.md │ ├── adr-0011-sorting-css-declarations.md │ ├── adr-0012-hello-prebuilt-storybook.md │ ├── adr-0013-replace-gitlab-ci-plus-clever-app-with-simple-object-storage-hosting-for-previews.md │ ├── adr-0014-why-we-internalized-leaflet-heat-and-simpleheat.md │ ├── adr-0015-introducing-a-custom-wds-plugin-based-on-esbuild.md │ ├── adr-0016-embracing-custom-elements-manifest.md │ ├── adr-0017-finding-accessible-colors-and-creating-design-tokens.md │ ├── adr-0018-how-to-give-feedback-after-a-user-action.md │ ├── adr-0019-how-to-make-toaster-accessible.md │ ├── adr-0020-making-the-component-theme-customisable.md │ ├── adr-0021-from-rem-to-em.md │ ├── adr-0022-new-icon-system.md │ ├── adr-0023-adding-stylelint.md │ ├── adr-0024-from-resize-mixin-to-resize-controller.md │ ├── adr-0025-moving-away-from-fieldset-legend.md │ ├── adr-0026-introducing-prettier.md │ ├── adr-0027-enabling-type-checking.md │ ├── adr-0028-making-our-component-apis-more-robust.md │ └── adr-0029-issues-with-the-disabled-attribute.md ├── cc-example-component.js ├── cc-example-component.smart.md ├── cc-example-component.stories.js ├── contributing │ ├── browser-support.md │ ├── forms.md │ ├── i18n.md │ ├── previews.md │ ├── release.md │ ├── resources.md │ ├── smart-component.md │ ├── stories.md │ ├── tasks.md │ ├── test.md │ ├── tools.md │ ├── wc-accessibility.md │ └── wc-guidelines.md ├── copywriting │ └── coming-soon.md ├── getting-started │ ├── accessibility.md │ ├── breaking-change-policy.md │ ├── breaking-down.md │ ├── browser-support.md │ ├── design-tokens.md │ ├── manual-installation.md │ ├── notification-system.md │ ├── smart-component.md │ ├── use-cdn.md │ └── use-npm.md ├── guidelines │ └── coming-soon.md └── translations.example.js ├── eslint.config.js ├── eslint ├── i18n │ ├── custom-rules │ │ ├── i18n-always-arrow-with-sanitize.js │ │ ├── i18n-always-sanitize-with-html.js │ │ ├── i18n-always-template-literal-sanitize.js │ │ ├── i18n-no-paramless-arrow.js │ │ ├── i18n-no-sanitize-without-html.js │ │ ├── i18n-order.js │ │ ├── i18n-shared.js │ │ ├── i18n-valid-key.js │ │ └── i18n-valid-value.js │ └── eslint-plugin-i18n.js ├── javascript │ └── eslint-config-clever-cloud-esm.js ├── lit-a11y │ └── eslint-config-lit-a11y-clever-cloud.js ├── lit │ └── eslint-config-lit-clever-cloud.js └── wc │ └── eslint-config-wc-clever-cloud.js ├── package-lock.json ├── package.json ├── prettier-rules └── sort-lit-get-properties.js ├── prettier.config.js ├── public ├── favicon.svg └── imgs │ ├── logo-clever-dark.svg │ └── logo-clever-light.svg ├── rollup ├── rollup-cdn-common.js ├── rollup-cdn-preview.config.js ├── rollup-cdn.config.js ├── rollup-common.js ├── rollup-npm.config.js ├── rollup-plugin-deps-manifest.js ├── rollup-plugin-index-generator.js └── rollup-plugin-styles-assets.js ├── sandbox ├── cc-ansi-palette │ ├── cc-ansi-palette-sandbox.js │ └── gogh-palettes.js ├── cc-kv-explorer │ └── cc-kv-explorer-sandbox.js ├── cc-logs-addon-runtime │ └── cc-logs-addon-runtime-sandbox.js ├── cc-logs-app-access │ └── cc-logs-app-access-sandbox.js ├── cc-logs-app-runtime │ └── cc-logs-app-runtime-sandbox.js ├── cc-logs │ └── cc-logs-sandbox.js ├── cc-product-card │ └── cc-product-card-sandbox.js ├── forms │ ├── form-demo-dynamic-form.js │ ├── form-demo-reset.js │ ├── form-demo-with-array-type.js │ ├── form-demo-with-cc-components.js │ ├── form-demo-with-coupled-inputs.js │ ├── form-demo-with-custom-error-message.js │ ├── form-demo-with-custom-validation.js │ ├── form-demo-with-fieldset.js │ ├── form-demo-with-native-inputs.js │ ├── form-demo-with-smart-component.js │ ├── form-demo-with-smart-component.types.d.ts │ └── forms-sandbox.js ├── index.html ├── index.js └── sandbox-styles.js ├── src ├── assets │ ├── arrows-left.svg │ ├── arrows-right.svg │ ├── cc-clever.icons.js │ ├── cc-remix.icons.js │ ├── git.svg │ ├── grafana.svg │ ├── info.svg │ ├── mail-line.svg │ ├── mail-star-line.svg │ ├── ram.svg │ ├── restart-failed.svg │ ├── restarting.svg │ ├── running.svg │ ├── start-failed.svg │ ├── starting.svg │ ├── unknown.svg │ └── world-110m.geo.js ├── components │ ├── cc-addon-admin │ │ ├── cc-addon-admin.events.js │ │ ├── cc-addon-admin.js │ │ ├── cc-addon-admin.stories.js │ │ └── cc-addon-admin.types.d.ts │ ├── cc-addon-backups │ │ ├── cc-addon-backups.js │ │ ├── cc-addon-backups.stories.js │ │ └── cc-addon-backups.types.d.ts │ ├── cc-addon-credentials │ │ ├── cc-addon-credentials.js │ │ ├── cc-addon-credentials.stories.js │ │ └── cc-addon-credentials.types.d.ts │ ├── cc-addon-elasticsearch-options │ │ ├── cc-addon-elasticsearch-options.js │ │ └── cc-addon-elasticsearch-options.stories.js │ ├── cc-addon-features │ │ ├── cc-addon-features.js │ │ ├── cc-addon-features.stories.js │ │ └── cc-addon-features.types.d.ts │ ├── cc-addon-jenkins-options │ │ ├── cc-addon-jenkins-options.js │ │ └── cc-addon-jenkins-options.stories.js │ ├── cc-addon-linked-apps │ │ ├── cc-addon-linked-apps.js │ │ ├── cc-addon-linked-apps.smart.js │ │ ├── cc-addon-linked-apps.smart.md │ │ ├── cc-addon-linked-apps.stories.js │ │ └── cc-addon-linked-apps.types.d.ts │ ├── cc-addon-mongodb-options │ │ ├── cc-addon-mongodb-options.js │ │ └── cc-addon-mongodb-options.stories.js │ ├── cc-addon-mysql-options │ │ ├── cc-addon-mysql-options.js │ │ └── cc-addon-mysql-options.stories.js │ ├── cc-addon-option-form │ │ ├── cc-addon-option-form.events.js │ │ ├── cc-addon-option-form.js │ │ └── cc-addon-option-form.stories.js │ ├── cc-addon-option │ │ ├── cc-addon-option.events.js │ │ ├── cc-addon-option.js │ │ └── cc-addon-option.stories.js │ ├── cc-addon-postgresql-options │ │ ├── cc-addon-postgresql-options.js │ │ └── cc-addon-postgresql-options.stories.js │ ├── cc-addon-redis-options │ │ ├── cc-addon-redis-options.js │ │ └── cc-addon-redis-options.stories.js │ ├── cc-ansi-palette │ │ ├── cc-ansi-palette.js │ │ └── cc-ansi-palette.stories.js │ ├── cc-article-card │ │ ├── cc-article-card.js │ │ ├── cc-article-card.stories.js │ │ └── cc-article-card.types.d.ts │ ├── cc-article-list │ │ ├── cc-article-list.js │ │ ├── cc-article-list.smart.js │ │ ├── cc-article-list.smart.md │ │ ├── cc-article-list.stories.js │ │ └── cc-article-list.types.d.ts │ ├── cc-badge │ │ ├── cc-badge.js │ │ ├── cc-badge.stories.js │ │ └── cc-badge.types.d.ts │ ├── cc-beta │ │ ├── cc-beta.js │ │ ├── cc-beta.stories.js │ │ └── cc-beta.types.d.ts │ ├── cc-block-details │ │ ├── cc-block-details.js │ │ └── cc-block-details.stories.js │ ├── cc-block-section │ │ ├── cc-block-section.js │ │ └── cc-block-section.stories.js │ ├── cc-block │ │ ├── cc-block.js │ │ ├── cc-block.stories.js │ │ └── cc-block.types.d.ts │ ├── cc-button │ │ ├── cc-button.js │ │ ├── cc-button.stories.js │ │ └── cc-button.types.d.ts │ ├── cc-datetime-relative │ │ ├── cc-datetime-relative.js │ │ ├── cc-datetime-relative.stories.js │ │ └── cc-datetime-relative.types.d.ts │ ├── cc-doc-card │ │ ├── cc-doc-card.js │ │ ├── cc-doc-card.stories.js │ │ └── cc-doc-card.types.d.ts │ ├── cc-doc-list │ │ ├── cc-doc-list.js │ │ ├── cc-doc-list.stories.js │ │ └── cc-doc-list.types.d.ts │ ├── cc-domain-management │ │ ├── cc-domain-management.events.js │ │ ├── cc-domain-management.js │ │ ├── cc-domain-management.smart.js │ │ ├── cc-domain-management.smart.md │ │ ├── cc-domain-management.stories.js │ │ └── cc-domain-management.types.d.ts │ ├── cc-elasticsearch-info │ │ ├── cc-elasticsearch-info.js │ │ ├── cc-elasticsearch-info.stories.js │ │ └── cc-elasticsearch-info.types.d.ts │ ├── cc-email-list │ │ ├── cc-email-list.events.js │ │ ├── cc-email-list.js │ │ ├── cc-email-list.smart.js │ │ ├── cc-email-list.smart.md │ │ ├── cc-email-list.stories.js │ │ └── cc-email-list.types.d.ts │ ├── cc-env-var-create │ │ ├── cc-env-var-create.events.js │ │ ├── cc-env-var-create.js │ │ └── cc-env-var-create.stories.js │ ├── cc-env-var-editor-expert │ │ ├── cc-env-var-editor-expert.js │ │ └── cc-env-var-editor-expert.stories.js │ ├── cc-env-var-editor-json │ │ ├── cc-env-var-editor-json.js │ │ └── cc-env-var-editor-json.stories.js │ ├── cc-env-var-editor-simple │ │ ├── cc-env-var-editor-simple.js │ │ └── cc-env-var-editor-simple.stories.js │ ├── cc-env-var-form │ │ ├── cc-env-var-form.events.js │ │ ├── cc-env-var-form.js │ │ ├── cc-env-var-form.smart-config-provider.js │ │ ├── cc-env-var-form.smart-config-provider.md │ │ ├── cc-env-var-form.smart-env-var-addon.js │ │ ├── cc-env-var-form.smart-env-var-addon.md │ │ ├── cc-env-var-form.smart-exposed-config.js │ │ ├── cc-env-var-form.smart-exposed-config.md │ │ ├── cc-env-var-form.stories.js │ │ └── cc-env-var-form.types.d.ts │ ├── cc-env-var-input │ │ ├── cc-env-var-input.events.js │ │ ├── cc-env-var-input.js │ │ ├── cc-env-var-input.stories.js │ │ └── cc-env-var-input.types.d.ts │ ├── cc-env-var-linked-services │ │ ├── cc-env-var-linked-services.js │ │ ├── cc-env-var-linked-services.stories.js │ │ └── cc-env-var-linked-services.types.d.ts │ ├── cc-expand │ │ ├── cc-expand.js │ │ └── cc-expand.stories.js │ ├── cc-grafana-info │ │ ├── cc-grafana-info.events.js │ │ ├── cc-grafana-info.js │ │ ├── cc-grafana-info.smart.js │ │ ├── cc-grafana-info.smart.md │ │ ├── cc-grafana-info.stories.js │ │ └── cc-grafana-info.types.d.ts │ ├── cc-header-addon │ │ ├── cc-header-addon.js │ │ ├── cc-header-addon.stories.js │ │ └── cc-header-addon.types.d.ts │ ├── cc-header-app │ │ ├── cc-header-app.events.js │ │ ├── cc-header-app.js │ │ ├── cc-header-app.stories.js │ │ └── cc-header-app.types.d.ts │ ├── cc-header-orga │ │ ├── cc-header-orga.js │ │ ├── cc-header-orga.stories.js │ │ └── cc-header-orga.types.d.ts │ ├── cc-heptapod-info │ │ ├── cc-heptapod-info.js │ │ ├── cc-heptapod-info.stories.js │ │ └── cc-heptapod-info.types.d.ts │ ├── cc-html-frame │ │ ├── cc-html-frame.js │ │ ├── cc-html-frame.stories.js │ │ └── cc-html-frame.types.d.ts │ ├── cc-icon │ │ ├── cc-icon.js │ │ ├── cc-icon.stories.js │ │ └── cc-icon.types.d.ts │ ├── cc-img │ │ ├── cc-img.js │ │ └── cc-img.stories.js │ ├── cc-input-date │ │ ├── cc-input-date.js │ │ ├── cc-input-date.stories.js │ │ ├── cc-input-date.test.js │ │ └── cc-input-date.types.d.ts │ ├── cc-input-number │ │ ├── cc-input-number.js │ │ └── cc-input-number.stories.js │ ├── cc-input-text │ │ ├── cc-input-text.events.js │ │ ├── cc-input-text.js │ │ └── cc-input-text.stories.js │ ├── cc-invoice-list │ │ ├── cc-invoice-list.js │ │ ├── cc-invoice-list.smart.js │ │ ├── cc-invoice-list.smart.md │ │ ├── cc-invoice-list.stories.js │ │ └── cc-invoice-list.types.d.ts │ ├── cc-invoice-table │ │ ├── cc-invoice-table.js │ │ ├── cc-invoice-table.stories.js │ │ └── cc-invoice-table.types.d.ts │ ├── cc-invoice │ │ ├── cc-invoice.js │ │ ├── cc-invoice.smart.js │ │ ├── cc-invoice.smart.md │ │ ├── cc-invoice.stories.js │ │ └── cc-invoice.types.d.ts │ ├── cc-jenkins-info │ │ ├── cc-jenkins-info.js │ │ ├── cc-jenkins-info.smart.js │ │ ├── cc-jenkins-info.smart.md │ │ ├── cc-jenkins-info.stories.js │ │ └── cc-jenkins-info.types.d.ts │ ├── cc-kv-explorer │ │ ├── cc-kv-explorer.events.js │ │ ├── cc-kv-explorer.js │ │ ├── cc-kv-explorer.smart.js │ │ ├── cc-kv-explorer.smart.md │ │ ├── cc-kv-explorer.stories.js │ │ ├── cc-kv-explorer.types.d.ts │ │ ├── kv-client.js │ │ ├── kv-details-ctrl.js │ │ ├── kv-key-editor-ctrl.js │ │ ├── kv-key-editor-hash-ctrl.js │ │ ├── kv-key-editor-list-ctrl.js │ │ ├── kv-key-editor-set-ctrl.js │ │ ├── kv-key-editor-string-ctrl.js │ │ ├── kv-keys-ctrl.js │ │ ├── kv-scanner.js │ │ ├── kv-terminal-ctrl.js │ │ ├── kv-utils.js │ │ └── kv-utils.test.js │ ├── cc-kv-hash-explorer │ │ ├── cc-kv-hash-explorer.events.js │ │ ├── cc-kv-hash-explorer.js │ │ ├── cc-kv-hash-explorer.stories.js │ │ └── cc-kv-hash-explorer.types.d.ts │ ├── cc-kv-hash-input │ │ ├── cc-kv-hash-input.js │ │ └── cc-kv-hash-input.stories.js │ ├── cc-kv-list-explorer │ │ ├── cc-kv-list-explorer.events.js │ │ ├── cc-kv-list-explorer.js │ │ ├── cc-kv-list-explorer.stories.js │ │ └── cc-kv-list-explorer.types.d.ts │ ├── cc-kv-list-input │ │ ├── cc-kv-list-input.js │ │ └── cc-kv-list-input.stories.js │ ├── cc-kv-set-explorer │ │ ├── cc-kv-set-explorer.events.js │ │ ├── cc-kv-set-explorer.js │ │ ├── cc-kv-set-explorer.stories.js │ │ └── cc-kv-set-explorer.types.d.ts │ ├── cc-kv-string-editor │ │ ├── cc-kv-string-editor.events.js │ │ ├── cc-kv-string-editor.js │ │ ├── cc-kv-string-editor.stories.js │ │ └── cc-kv-string-editor.types.d.ts │ ├── cc-kv-terminal │ │ ├── cc-kv-terminal.events.js │ │ ├── cc-kv-terminal.js │ │ ├── cc-kv-terminal.stories.js │ │ └── cc-kv-terminal.types.d.ts │ ├── cc-loader │ │ ├── cc-loader.js │ │ └── cc-loader.stories.js │ ├── cc-logs-addon-runtime │ │ ├── cc-logs-addon-runtime.js │ │ ├── cc-logs-addon-runtime.smart.js │ │ ├── cc-logs-addon-runtime.smart.md │ │ ├── cc-logs-addon-runtime.stories.js │ │ └── cc-logs-addon-runtime.types.d.ts │ ├── cc-logs-app-access │ │ ├── cc-logs-app-access.js │ │ ├── cc-logs-app-access.smart.js │ │ ├── cc-logs-app-access.smart.md │ │ ├── cc-logs-app-access.stories.js │ │ └── cc-logs-app-access.types.d.ts │ ├── cc-logs-app-runtime │ │ ├── cc-logs-app-runtime.js │ │ ├── cc-logs-app-runtime.smart.js │ │ ├── cc-logs-app-runtime.smart.md │ │ ├── cc-logs-app-runtime.stories.js │ │ └── cc-logs-app-runtime.types.d.ts │ ├── cc-logs-control │ │ ├── cc-logs-control.events.js │ │ ├── cc-logs-control.js │ │ ├── cc-logs-control.stories.js │ │ └── cc-logs-control.types.d.ts │ ├── cc-logs-date-range-selector │ │ ├── cc-logs-date-range-selector.events.js │ │ ├── cc-logs-date-range-selector.js │ │ ├── cc-logs-date-range-selector.stories.js │ │ ├── cc-logs-date-range-selector.types.d.ts │ │ ├── date-range-selection.js │ │ └── date-range-selection.test.js │ ├── cc-logs-instances │ │ ├── cc-logs-instances.events.js │ │ ├── cc-logs-instances.js │ │ ├── cc-logs-instances.stories.js │ │ └── cc-logs-instances.types.d.ts │ ├── cc-logs-loading-progress │ │ ├── cc-logs-loading-progress-state-builder.js │ │ ├── cc-logs-loading-progress.events.js │ │ ├── cc-logs-loading-progress.js │ │ ├── cc-logs-loading-progress.stories.js │ │ └── cc-logs-loading-progress.types.d.ts │ ├── cc-logs-message-filter │ │ ├── cc-logs-message-filter.events.js │ │ ├── cc-logs-message-filter.js │ │ ├── cc-logs-message-filter.stories.js │ │ └── cc-logs-message-filter.types.d.ts │ ├── cc-logs │ │ ├── animation-runner.js │ │ ├── cc-logs.events.js │ │ ├── cc-logs.js │ │ ├── cc-logs.stories.js │ │ ├── cc-logs.types.d.ts │ │ ├── date-display.types.d.ts │ │ ├── date-displayer.js │ │ ├── date-displayer.test.js │ │ ├── logs-controller.js │ │ ├── logs-controller.test.js │ │ └── logs-input-controller.js │ ├── cc-logsmap │ │ ├── cc-logsmap.events.js │ │ ├── cc-logsmap.js │ │ ├── cc-logsmap.stories.js │ │ └── cc-logsmap.types.d.ts │ ├── cc-map-marker-dot │ │ ├── cc-map-marker-dot.js │ │ └── cc-map-marker-dot.stories.js │ ├── cc-map-marker-server │ │ ├── cc-map-marker-server.js │ │ ├── cc-map-marker-server.stories.js │ │ └── cc-map-marker-server.types.d.ts │ ├── cc-map │ │ ├── cc-map.events.js │ │ ├── cc-map.js │ │ ├── cc-map.stories.js │ │ └── cc-map.types.d.ts │ ├── cc-matomo-info │ │ ├── cc-matomo-info.js │ │ ├── cc-matomo-info.stories.js │ │ └── cc-matomo-info.types.d.ts │ ├── cc-notice │ │ ├── cc-notice.events.js │ │ ├── cc-notice.js │ │ ├── cc-notice.stories.js │ │ └── cc-notice.types.d.ts │ ├── cc-oauth-consumer-form │ │ ├── cc-oauth-consumer-form.events.js │ │ ├── cc-oauth-consumer-form.js │ │ ├── cc-oauth-consumer-form.smart-create.js │ │ ├── cc-oauth-consumer-form.smart-create.md │ │ ├── cc-oauth-consumer-form.smart-update.js │ │ ├── cc-oauth-consumer-form.smart-update.md │ │ ├── cc-oauth-consumer-form.stories.js │ │ └── cc-oauth-consumer-form.types.d.ts │ ├── cc-oauth-consumer-info │ │ ├── cc-oauth-consumer-info.js │ │ ├── cc-oauth-consumer-info.smart.js │ │ ├── cc-oauth-consumer-info.smart.md │ │ ├── cc-oauth-consumer-info.stories.js │ │ └── cc-oauth-consumer-info.types.d.ts │ ├── cc-order-summary │ │ ├── cc-order-summary.events.js │ │ ├── cc-order-summary.js │ │ ├── cc-order-summary.stories.js │ │ └── cc-order-summary.types.d.ts │ ├── cc-orga-member-card │ │ ├── cc-orga-member-card.events.js │ │ ├── cc-orga-member-card.js │ │ ├── cc-orga-member-card.stories.js │ │ └── cc-orga-member-card.types.d.ts │ ├── cc-orga-member-list │ │ ├── cc-orga-member-list.events.js │ │ ├── cc-orga-member-list.js │ │ ├── cc-orga-member-list.smart.js │ │ ├── cc-orga-member-list.smart.md │ │ ├── cc-orga-member-list.stories.js │ │ └── cc-orga-member-list.types.d.ts │ ├── cc-overview │ │ ├── cc-overview.js │ │ ├── cc-overview.stories.js │ │ └── cc-overview.types.d.ts │ ├── cc-plan-item │ │ ├── cc-plan-item.js │ │ ├── cc-plan-item.stories.js │ │ └── cc-plan-item.types.d.ts │ ├── cc-plan-picker │ │ ├── cc-plan-picker.js │ │ ├── cc-plan-picker.stories.js │ │ └── cc-plan-picker.types.d.ts │ ├── cc-popover │ │ ├── cc-popover.js │ │ ├── cc-popover.stories.js │ │ └── cc-popover.types.d.ts │ ├── cc-pricing-estimation │ │ ├── cc-pricing-estimation.js │ │ ├── cc-pricing-estimation.smart.js │ │ ├── cc-pricing-estimation.smart.md │ │ ├── cc-pricing-estimation.stories.js │ │ └── cc-pricing-estimation.types.d.ts │ ├── cc-pricing-header │ │ ├── cc-pricing-header.js │ │ ├── cc-pricing-header.smart.js │ │ ├── cc-pricing-header.smart.md │ │ ├── cc-pricing-header.stories.js │ │ └── cc-pricing-header.types.d.ts │ ├── cc-pricing-page │ │ ├── cc-pricing-page.events.js │ │ ├── cc-pricing-page.js │ │ ├── cc-pricing-page.stories.js │ │ └── cc-pricing-page.types.d.ts │ ├── cc-pricing-product-consumption │ │ ├── cc-pricing-product-consumption.js │ │ ├── cc-pricing-product-consumption.smart.js │ │ ├── cc-pricing-product-consumption.smart.md │ │ ├── cc-pricing-product-consumption.stories.js │ │ └── cc-pricing-product-consumption.types.d.ts │ ├── cc-pricing-product │ │ ├── cc-pricing-product.js │ │ ├── cc-pricing-product.smart-addon.js │ │ ├── cc-pricing-product.smart-addon.md │ │ ├── cc-pricing-product.smart-runtime.js │ │ ├── cc-pricing-product.smart-runtime.md │ │ ├── cc-pricing-product.stories.js │ │ └── cc-pricing-product.types.d.ts │ ├── cc-product-card │ │ ├── cc-product-card.js │ │ ├── cc-product-card.stories.js │ │ ├── cc-product-card.types.d.ts │ │ └── generate-random-keywords.js │ ├── cc-product-list │ │ ├── cc-product-list.js │ │ ├── cc-product-list.stories.js │ │ ├── cc-product-list.types.d.ts │ │ ├── products-controller.js │ │ └── products-controller.test.js │ ├── cc-select │ │ ├── cc-select.js │ │ ├── cc-select.stories.js │ │ └── cc-select.types.d.ts │ ├── cc-smart-container │ │ └── cc-smart-container.js │ ├── cc-ssh-key-list │ │ ├── cc-ssh-key-list.events.js │ │ ├── cc-ssh-key-list.js │ │ ├── cc-ssh-key-list.smart.js │ │ ├── cc-ssh-key-list.smart.md │ │ ├── cc-ssh-key-list.stories.js │ │ └── cc-ssh-key-list.types.d.ts │ ├── cc-stretch │ │ ├── cc-stretch.js │ │ └── cc-stretch.stories.js │ ├── cc-tcp-redirection-form │ │ ├── cc-tcp-redirection-form.js │ │ ├── cc-tcp-redirection-form.smart.js │ │ ├── cc-tcp-redirection-form.smart.md │ │ ├── cc-tcp-redirection-form.stories.js │ │ └── cc-tcp-redirection-form.types.d.ts │ ├── cc-tcp-redirection │ │ ├── cc-tcp-redirection.events.js │ │ ├── cc-tcp-redirection.js │ │ ├── cc-tcp-redirection.stories.js │ │ └── cc-tcp-redirection.types.d.ts │ ├── cc-tile-deployments │ │ ├── cc-tile-deployments.js │ │ ├── cc-tile-deployments.stories.js │ │ └── cc-tile-deployments.types.d.ts │ ├── cc-tile-instances │ │ ├── cc-tile-instances.js │ │ ├── cc-tile-instances.stories.js │ │ └── cc-tile-instances.types.d.ts │ ├── cc-tile-metrics │ │ ├── cc-tile-metrics.js │ │ ├── cc-tile-metrics.smart.js │ │ ├── cc-tile-metrics.smart.md │ │ ├── cc-tile-metrics.stories.js │ │ └── cc-tile-metrics.types.d.ts │ ├── cc-tile-requests │ │ ├── cc-tile-requests.js │ │ ├── cc-tile-requests.stories.js │ │ └── cc-tile-requests.types.d.ts │ ├── cc-tile-scalability │ │ ├── cc-tile-scalability.js │ │ ├── cc-tile-scalability.stories.js │ │ └── cc-tile-scalability.types.d.ts │ ├── cc-tile-status-codes │ │ ├── cc-tile-status-codes.js │ │ ├── cc-tile-status-codes.smart.js │ │ ├── cc-tile-status-codes.smart.md │ │ ├── cc-tile-status-codes.stories.js │ │ └── cc-tile-status-codes.types.d.ts │ ├── cc-toast │ │ ├── cc-toast.events.js │ │ ├── cc-toast.js │ │ └── cc-toast.stories.js │ ├── cc-toaster │ │ ├── cc-toaster.js │ │ ├── cc-toaster.stories.js │ │ └── cc-toaster.types.d.ts │ ├── cc-toggle │ │ ├── cc-toggle.js │ │ ├── cc-toggle.stories.js │ │ └── cc-toggle.types.d.ts │ ├── cc-token-api-creation-form │ │ ├── cc-token-api-creation-form.events.js │ │ ├── cc-token-api-creation-form.js │ │ ├── cc-token-api-creation-form.smart.js │ │ ├── cc-token-api-creation-form.smart.md │ │ ├── cc-token-api-creation-form.stories.js │ │ └── cc-token-api-creation-form.types.d.ts │ ├── cc-token-api-list │ │ ├── cc-token-api-list.js │ │ ├── cc-token-api-list.smart.js │ │ ├── cc-token-api-list.smart.md │ │ ├── cc-token-api-list.stories.js │ │ └── cc-token-api-list.types.d.ts │ ├── cc-token-api-update-form │ │ ├── cc-token-api-update-form.events.js │ │ ├── cc-token-api-update-form.js │ │ ├── cc-token-api-update-form.smart.js │ │ ├── cc-token-api-update-form.smart.md │ │ ├── cc-token-api-update-form.stories.js │ │ └── cc-token-api-update-form.types.d.ts │ ├── cc-token-oauth-list │ │ ├── cc-token-oauth-list.js │ │ ├── cc-token-oauth-list.smart.js │ │ ├── cc-token-oauth-list.smart.md │ │ ├── cc-token-oauth-list.stories.js │ │ └── cc-token-oauth-list.types.d.ts │ ├── cc-token-session-list │ │ ├── cc-token-session-list.js │ │ ├── cc-token-session-list.smart.js │ │ ├── cc-token-session-list.smart.md │ │ ├── cc-token-session-list.stories.js │ │ └── cc-token-session-list.types.d.ts │ ├── cc-warning-payment │ │ ├── cc-warning-payment.js │ │ ├── cc-warning-payment.stories.js │ │ └── cc-warning-payment.types.d.ts │ ├── cc-zone-card │ │ ├── cc-zone-card.js │ │ ├── cc-zone-card.stories.js │ │ └── cc-zone-card.types.d.ts │ ├── cc-zone-input │ │ ├── cc-zone-input.js │ │ ├── cc-zone-input.stories.js │ │ └── cc-zone-input.types.d.ts │ ├── cc-zone-picker │ │ ├── cc-zone-picker.js │ │ ├── cc-zone-picker.stories.js │ │ └── cc-zone-picker.types.d.ts │ ├── cc-zone │ │ ├── cc-zone.js │ │ ├── cc-zone.stories.js │ │ └── cc-zone.types.d.ts │ ├── common.events.js │ └── common.types.d.ts ├── controllers │ ├── lost-focus-controller.js │ ├── lost-focus-controller.md │ ├── lost-focus-controller.stories.js │ ├── resize-controller.js │ ├── resize-controller.md │ └── resize-controller.stories.js ├── directives │ ├── has-slotted-children.js │ └── has-slotted-children.test.js ├── lib │ ├── animate.js │ ├── ansi │ │ ├── ansi-palette-analyser.js │ │ ├── ansi-palette-style.js │ │ ├── ansi.js │ │ ├── ansi.types.d.ts │ │ └── palettes │ │ │ ├── default.js │ │ │ ├── everblush.js │ │ │ ├── hyoob.js │ │ │ ├── night-owl.js │ │ │ ├── one-light.js │ │ │ └── tokyo-night-light.js │ ├── api-helpers.js │ ├── buffer.js │ ├── change-case.js │ ├── clipboard.js │ ├── color.js │ ├── color.types.d.ts │ ├── css-custom-properties.js │ ├── date │ │ ├── date-formatter.js │ │ ├── date-range-utils.js │ │ ├── date-range.types.d.ts │ │ ├── date-utils.js │ │ └── date.types.d.ts │ ├── dom.js │ ├── domain.js │ ├── events-map.types.d.ts │ ├── events.js │ ├── events.types.d.ts │ ├── fake-strings.js │ ├── focus-helper.js │ ├── form │ │ ├── cc-form-control-element.abstract.js │ │ ├── form-error-focus-controller.js │ │ ├── form-submit-directive.js │ │ ├── form-submit-handler.js │ │ ├── form-utils.js │ │ ├── form.events.js │ │ ├── form.types.d.ts │ │ ├── validation.js │ │ └── validation.types.d.ts │ ├── i18n │ │ ├── i18n-date.js │ │ ├── i18n-display.js │ │ ├── i18n-number.js │ │ ├── i18n-sanitize.js │ │ ├── i18n-string.js │ │ ├── i18n.js │ │ └── i18n.types.d.ts │ ├── immer.js │ ├── leaflet │ │ ├── leaflet-esm.js │ │ ├── leaflet-heat.js │ │ ├── simpleheat.js │ │ └── tsconfig-empty.json │ ├── logs │ │ ├── logs-progress.js │ │ ├── logs-stream.js │ │ └── logs-stream.types.d.ts │ ├── memory-cache.js │ ├── notifications.events.js │ ├── notifications.js │ ├── pricing.js │ ├── pricing.types.d.ts │ ├── product.js │ ├── regex-parse.js │ ├── remote-assets.js │ ├── send-to-api.events.js │ ├── send-to-api.js │ ├── send-to-api.types.d.ts │ ├── send-to-auth-bridge.js │ ├── shadow-dom-utils.js │ ├── smart │ │ ├── define-smart-component.js │ │ ├── smart-component.types.d.ts │ │ ├── smart-manager.js │ │ └── smart-symbols.js │ ├── tokens.js │ ├── tokens.types.d.ts │ ├── utils.js │ ├── xml-parser.js │ └── zone.js ├── stories │ ├── all-form-controls.js │ ├── assets │ │ ├── bold.svg │ │ ├── center.svg │ │ ├── clevercloud.svg │ │ ├── close.svg │ │ ├── cloudtemple.svg │ │ ├── console.png │ │ ├── italic.svg │ │ ├── justify.svg │ │ ├── left.svg │ │ ├── oracle.svg │ │ ├── ovh.svg │ │ ├── right.svg │ │ ├── scaleway.svg │ │ ├── underline.svg │ │ └── warning.svg │ ├── cc-pricing-page-sandbox.js │ ├── fixtures │ │ ├── 24-hours-points.js │ │ ├── addon-backups-data.js │ │ ├── addon-plans.js │ │ ├── consumption-plans.js │ │ ├── country-city-points-big-orga.js │ │ ├── country-city-points-medium-orga.js │ │ ├── country-city-points-normal-orga.js │ │ ├── domains.js │ │ ├── fake-map-data.js │ │ ├── invoices.js │ │ ├── logs-instance.js │ │ ├── logs.js │ │ ├── long-member-list.js │ │ ├── plans.js │ │ ├── price-system.js │ │ ├── runtime-plans.js │ │ └── zones.js │ └── lib │ │ ├── autodocs-template.jsx │ │ ├── dom.js │ │ ├── i18n-control.js │ │ ├── make-story.js │ │ ├── markdown-docs.jsx │ │ ├── markdown-indexer.js │ │ ├── markdown-to-csf.js │ │ ├── sequence.js │ │ ├── smart-auth-plugin.js │ │ ├── story-names.js │ │ └── timers.js ├── styles │ ├── accessibility.js │ ├── cli-commands.js │ ├── default-theme.css │ ├── info-tiles.js │ ├── leaflet.js │ ├── shoelace.js │ ├── skeleton.js │ ├── undefined-components.css │ └── waiting.js ├── templates │ ├── cc-addon-encryption-at-rest-option │ │ └── cc-addon-encryption-at-rest-option.js │ └── cc-link │ │ ├── cc-link.js │ │ ├── cc-link.md │ │ └── cc-link.stories.js └── translations │ ├── translation.js │ ├── translation.types.d.ts │ ├── translations.en.js │ └── translations.fr.js ├── tasks ├── cdn-cli.js ├── cdn-entry-name.js ├── cdn-environments.js ├── cdn-manager.js ├── cellar-client.js ├── check-i18n.js ├── check-type-imports.js ├── component-usage-cli.js ├── component-usage-graph.js ├── generate-events-map.js ├── generate-icons-assets.js ├── git-utils.js ├── preview.js └── typechecking-stats.js ├── test-mocha ├── cem │ ├── fixtures │ │ ├── cc-test-component.js │ │ ├── cc-test-component.types.d.ts │ │ ├── cem-test-import │ │ │ └── cc-test-imports-sub.types.d.ts │ │ ├── common.types.d.ts │ │ └── test-imports.types.d.ts │ └── support-typedef-jsdoc-utils.test.js ├── i18n │ ├── eslint-custom-rules.test.js │ ├── i18n-always-arrow-with-sanitize.test-data.js │ ├── i18n-always-sanitize-with-html.test-data.js │ ├── i18n-always-template-literal-sanitize.test-data.js │ ├── i18n-no-paramless-arrow.test-data.js │ ├── i18n-no-sanitize-without-html.test-data.js │ ├── i18n-order.test-data.js │ ├── i18n-valid-key.test-data.js │ └── i18n-valid-value.test-data.js └── prettier │ └── sort-lit-get-properties.test.js ├── test ├── ansi │ ├── ansi-palettes.test.js │ └── ansi.test.js ├── buffer.test.js ├── change-case.test.js ├── controller │ └── lost-focus-controller.test.js ├── date │ ├── date-formatter.test.js │ ├── date-range-utils.test.js │ └── date-utils.test.js ├── dom │ ├── dom.css │ ├── dom.suite.js │ └── dom.test.html ├── form │ ├── cc-form-control-element.abstract.test.js │ ├── form-submit-directive.test.js │ ├── form-utils.test.js │ └── validation.test.js ├── helpers │ ├── element-helper.js │ ├── mock-now.js │ ├── test-stories.js │ └── test-stories.types.d.ts ├── i18n │ ├── i18n-number.test.js │ ├── i18n-sanitize.test.js │ └── i18n-string.test.js ├── logs │ ├── logs-progress.test.js │ └── logs-stream.test.js ├── memory-cache.test.js ├── pricing.test.js ├── regex-parse.test.js ├── shadow-dom-utils.test.js ├── smart │ ├── smart-manager.suite.js │ └── smart-manager.test.html ├── tokens │ └── tokens.test.js ├── utils.test.js ├── xml-file-test.xml └── xml-parser.test.js ├── tsconfig.ci.json ├── tsconfig.json ├── wds ├── cem-analyzer-plugin.js ├── esbuild-bundle-plugin.js ├── test-stories-plugin.js └── wds-common.js └── web-test-runner.config.js /.commitlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # run `git config blame.ignoreRevsFile .git-blame-ignore-revs` locally to apply 2 | 3 | # chore: format all remaining files with the format command 4 | a166f4f8da4902a37bf7ef9654186c9b6ef442c4 5 | 6 | # chore: update source code with Prettier and Stylelint update 7 | f9fcd572efca5301e44ae348ec5eb2c41b37e931 8 | 9 | # refactor: apply the new project file structure 10 | 79f7a4893dfb5194a2fb06d781c67766a5aa9349 11 | -------------------------------------------------------------------------------- /.githooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | npx --no -- commitlint --edit 4 | -------------------------------------------------------------------------------- /.githooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | protected_branch='master' 4 | current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') 5 | 6 | if [ "$protected_branch" = "$current_branch" ] 7 | then 8 | read -p "You're about to push to ${protected_branch} branch, is that what you intended? [y|n] " -n 1 -r < /dev/tty 9 | echo 10 | if echo "$REPLY" | grep -E '^[Yy]$' > /dev/null 11 | then 12 | exit 0 13 | fi 14 | exit 1 15 | else 16 | exit 0 17 | fi 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/accessibility-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Accessibility issue 3 | about: Use this template to properly report an accessibility issue 4 | title: 'cc-xxx: accessibility issue' 5 | labels: a11y 6 | assignees: '' 7 | --- 8 | 9 | ## Accessibility issue 10 | 11 | 15 | 16 | ## Description of the issue 17 | 18 | - User Impact/Description: 19 | - WCAG Criterion: 20 | 21 | ### Context about the issue 22 | 23 | 24 | 25 | - Impacted component(s): 26 | - Browser(s): 27 | - Assistive technologies: 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - 'hotfix/**' 6 | name: release 7 | jobs: 8 | release: 9 | name: release 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Extract branch name 13 | run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV 14 | - uses: google-github-actions/release-please-action@v3 15 | id: release 16 | with: 17 | token: ${{ secrets.CI_TOKEN }} 18 | release-type: node 19 | include-v-in-tag: false 20 | default-branch: ${{ env.BRANCH_NAME }} 21 | changelog-types: '[{"type": "feat", "section": "🚀 Features"}, {"type": "fix", "section": "🐛 Bug Fixes"}, {"type": "perf", "section": "💪 Performance Improvements"}, {"type": "deps", "section": "🗃️ Dependencies", "hidden": true}, {"type": "revert", "section": "↩ Reverts"}, {"type": "docs", "section": "📖 Documentation", "hidden": true}, {"type": "style", "section": "🎨 Styles", "hidden": true}, {"type": "chore", "section": "🧹 Miscellaneous Chores", "hidden": true}, {"type": "refactor", "section": "🛠 Code Refactoring", "hidden": true}, {"type": "test", "section": "🔬 Tests", "hidden": true}, {"type": "build", "section": "🏗️ Build System", "hidden": true}, {"type": "ci", "section": "🤖 Continuous Integration", "hidden": true}]' 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.s3cfg 3 | .env* 4 | .preview-index.html 5 | .preview-manifest.json 6 | dist 7 | dist-cdn 8 | node_modules 9 | storybook-static 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix = "" 2 | message = "Upgrade to %s" 3 | preid = "beta" 4 | loglevel = "error" 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore assets 2 | src/assets 3 | src/stories/assets 4 | 5 | # Ignore fixtures 6 | src/stories/fixtures 7 | test-mocha/cem/fixtures 8 | 9 | # Ignore MD files 10 | **/*.md 11 | -------------------------------------------------------------------------------- /.storybook/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | 3 | # If an existing asset or directory is requested, serve it 4 | RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] 5 | RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d 6 | RewriteRule ^ - [L] 7 | 8 | 9 | 10 | Header set Cache-Control "no-cache" 11 | 12 | 13 | 14 | Header set Cache-Control "max-age=2592000, immutable" 15 | 16 | 17 | 18 | Header set Cache-Control "max-age=31536000, immutable" 19 | 20 | 21 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from '@storybook/manager-api'; 2 | import { create } from '@storybook/theming'; 3 | import { enhanceStoryName } from '../src/stories/lib/story-names.js'; 4 | 5 | // We could create an addon to provide a control that would switch between dark / light 6 | // but it would only switch the UI theme, not the stories so right now it's not worth it 7 | const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; 8 | 9 | const cleverTheme = create({ 10 | base: isDarkMode ? 'dark' : 'light', 11 | brandTitle: 'Clever Cloud components', 12 | brandUrl: 'https://www.clever-cloud.com/doc/', 13 | brandImage: isDarkMode ? 'imgs/logo-clever-dark.svg' : 'imgs/logo-clever-light.svg', 14 | }); 15 | 16 | addons.setConfig({ 17 | theme: cleverTheme, 18 | sidebar: { 19 | collapsedRoots: ['📖-guidelines', '🖋-copywriting', '👋-contributing', '📌-architecture-decision-records'], 20 | renderLabel: ({ name, type }) => (type === 'story' ? enhanceStoryName(name) : name), 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-order"], 4 | "customSyntax": "postcss-styled-syntax", 5 | "rules": { 6 | "order/properties-alphabetical-order": true, 7 | "no-duplicate-selectors": true, 8 | "color-hex-length": "short", 9 | "selector-attribute-quotes": "always", 10 | "value-no-vendor-prefix": true, 11 | "font-weight-notation": "named-where-possible", 12 | "font-family-name-quotes": "always-unless-keyword", 13 | "comment-whitespace-inside": "always", 14 | "comment-empty-line-before": null, 15 | "rule-empty-line-before": [ 16 | "always-multi-line", 17 | { 18 | "except": ["first-nested", "after-single-line-comment"], 19 | "ignore": ["after-comment"] 20 | } 21 | ], 22 | "selector-pseudo-element-colon-notation": "double", 23 | "media-feature-name-no-vendor-prefix": true, 24 | "no-descending-specificity": null, 25 | "declaration-block-no-redundant-longhand-properties": null, 26 | "property-no-vendor-prefix": null, 27 | "selector-class-pattern": [ 28 | "^([a-z][a-z0-9]*)((-{1,2}|_{1,2})[a-z0-9]+)*$", 29 | { 30 | "message": "Expected class selector to be either kebab-case, kebab--case or snake__case" 31 | } 32 | ], 33 | "selector-id-pattern": [ 34 | "^([a-z][a-z0-9]*)((-{1,2}|_{1,2})[a-z0-9]+)*$", 35 | { 36 | "message": "Expected id selector to be either kebab-case, kebab--case or snake__case" 37 | } 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cdn-ui/cors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GET 4 | * 5 | 6 | 7 | -------------------------------------------------------------------------------- /cem/add-dependencies-in-description.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CEM analyzer plugin: add-dependencies-in-description 3 | * 4 | * This plugin adds the dependencies and the dependants at the description of each component if they have some. 5 | */ 6 | import { getComponentsGraph, getComponentsTree } from '../tasks/component-usage-graph.js'; 7 | 8 | const graph = await getComponentsGraph(); 9 | 10 | export default function addDependenciesInDescription() { 11 | return { 12 | name: 'add-dependencies-in-description', 13 | moduleLinkPhase({ moduleDoc }) { 14 | const isComponent = moduleDoc.path.includes('src/components/'); 15 | const isSmartComponent = moduleDoc.path.includes('.smart'); 16 | 17 | const shouldProcess = isComponent && !isSmartComponent; 18 | const dependencies = shouldProcess ? getComponentsTree([moduleDoc.path], graph, 'dependencies') : ''; 19 | const dependants = shouldProcess ? getComponentsTree([moduleDoc.path], graph, 'dependants', 1) : ''; 20 | 21 | let sourceLine = ''; 22 | if (dependencies !== '') { 23 | sourceLine += '### Dependencies\n' + '```\n' + dependencies + '\n```'; 24 | } 25 | if (dependants !== '') { 26 | sourceLine += '\n\n### Dependants\n' + '```\n' + dependants + '\n```'; 27 | } 28 | 29 | moduleDoc.declarations 30 | ?.filter((declaration) => declaration.kind === 'class') 31 | ?.forEach((declaration) => { 32 | declaration.description += '\n\n' + sourceLine; 33 | }); 34 | }, 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /cem/add-github-source-in-description.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CEM analyzer plugin: add-github-source-in-description 3 | * 4 | * This plugin adds the public GitHub source in the description of each element. 5 | * It adds it at the beginning of the description, just after the first empty line. 6 | */ 7 | export default function addGithubSourceInDescription(options = {}) { 8 | const { githubProject } = options; 9 | return { 10 | name: 'add-github-source-in-description', 11 | moduleLinkPhase({ moduleDoc }) { 12 | const sourceLine = `🧐 [component's source code on GitHub](https://github.com/${githubProject}/blob/master/${moduleDoc.path})`; 13 | 14 | moduleDoc.declarations 15 | ?.filter((declaration) => declaration.kind === 'class') 16 | ?.forEach((declaration) => { 17 | const descriptionLines = declaration.description.split('\n'); 18 | const firstEmptyLineIndex = descriptionLines.findIndex((line) => line === ''); 19 | if (firstEmptyLineIndex === -1) { 20 | descriptionLines.push('', sourceLine); 21 | } else { 22 | descriptionLines.splice(firstEmptyLineIndex, 0, '', sourceLine); 23 | } 24 | declaration.description = descriptionLines.join('\n'); 25 | }); 26 | }, 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /cem/remove-private-members.js: -------------------------------------------------------------------------------- 1 | function isPrivate(item) { 2 | return item.name.startsWith('_'); 3 | } 4 | 5 | /** 6 | * CEM analyzer plugin: remove-private-members 7 | * 8 | * This plugin removes private fields from CEM. 9 | * It relies on the "_" prefix convention to identify private members of a class. 10 | */ 11 | export default function removePrivateMembers() { 12 | return { 13 | name: 'remove-private-members', 14 | packageLinkPhase({ customElementsManifest }) { 15 | customElementsManifest?.modules?.forEach((module) => { 16 | module?.declarations?.forEach((declaration) => { 17 | if (declaration.members != null) { 18 | declaration.members = declaration.members.filter((member) => { 19 | const propertyOrMethod = member.kind === 'field' || member.kind === 'method'; 20 | return !(propertyOrMethod && isPrivate(member)); 21 | }); 22 | } 23 | 24 | if (declaration.attributes != null) { 25 | declaration.attributes = declaration.attributes.filter((attribute) => { 26 | return !isPrivate(attribute); 27 | }); 28 | } 29 | }); 30 | }); 31 | }, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /cem/sort-items.js: -------------------------------------------------------------------------------- 1 | import { sortBy } from '../src/lib/utils.js'; 2 | 3 | /** 4 | * CEM analyzer plugin: sort-items 5 | * 6 | * This plugin sorts all items alphabetically by their name. 7 | * This is very useful when you want to diff different manifests. 8 | */ 9 | export default function sortItems() { 10 | return { 11 | name: 'sort-items', 12 | packageLinkPhase({ customElementsManifest }) { 13 | if (customElementsManifest.modules == null) { 14 | return; 15 | } 16 | 17 | for (const module of customElementsManifest.modules) { 18 | if (module.declarations != null) { 19 | for (const declaration of module.declarations) { 20 | declaration.attributes?.sort(sortBy('name')); 21 | declaration.cssParts?.sort(sortBy('name')); 22 | declaration.cssProperties?.sort(sortBy('name')); 23 | declaration.events?.sort(sortBy('name')); 24 | declaration.members?.sort(sortBy('name')); 25 | declaration.slots?.sort(sortBy('name')); 26 | } 27 | } 28 | } 29 | }, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /custom-elements-manifest.config.mjs: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import addDependenciesInDescription from './cem/add-dependencies-in-description.js'; 3 | import addGithubSourceInDescription from './cem/add-github-source-in-description.js'; 4 | import identifyReadonlyMembers from './cem/identify-readonly-members.js'; 5 | import listImages from './cem/list-images.js'; 6 | import removePrivateMembers from './cem/remove-private-members.js'; 7 | import sortItems from './cem/sort-items.js'; 8 | import supportCcEvents from './cem/support-cc-events.js'; 9 | import supportCssdisplayJsdoc from './cem/support-cssdisplay-jsdoc.js'; 10 | import supportTypedefJsdoc from './cem/support-typedef-jsdoc.js'; 11 | 12 | // Temporary for now 13 | fs.mkdirSync('dist', { recursive: true }); 14 | 15 | export default { 16 | globs: ['src/components/**/cc-*.js', 'src/lib/form/cc-form-control-element.abstract.js'], 17 | exclude: ['src/**/*.stories.js'], 18 | litelement: true, 19 | // dev: true, 20 | // watch: true, 21 | plugins: [ 22 | supportCcEvents(), 23 | sortItems(), 24 | removePrivateMembers(), 25 | identifyReadonlyMembers(), 26 | supportCssdisplayJsdoc(), 27 | supportTypedefJsdoc(), 28 | addDependenciesInDescription(), 29 | addGithubSourceInDescription({ githubProject: 'CleverCloud/clever-components' }), 30 | listImages(), 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /custom-elements.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": "1.0.0", 3 | "readme": "", 4 | "modules": [] 5 | } 6 | -------------------------------------------------------------------------------- /demo-smart/index.js: -------------------------------------------------------------------------------- 1 | import '../src/components/cc-toaster/cc-toaster.js'; 2 | import { addTranslations, setLanguage } from '../src/lib/i18n/i18n.js'; 3 | import { updateRootContext } from '../src/lib/smart/smart-manager.js'; 4 | import { lang, translations } from '../src/translations/translations.en.js'; 5 | 6 | addTranslations(lang, translations); 7 | setLanguage(lang); 8 | 9 | updateRootContext({}); 10 | 11 | window.addEventListener('cc-notify', (event) => { 12 | document.querySelector('cc-toaster').show(event.detail); 13 | }); 14 | 15 | const { definition, ...componentProperties } = Object.fromEntries(new URL(document.location).searchParams.entries()); 16 | const componentName = definition.split('.').shift(); 17 | 18 | import(`../src/components/${componentName}/${definition}.js`); 19 | 20 | const $container = document.querySelector('cc-smart-container'); 21 | 22 | const $component = document.createElement(componentName); 23 | for (const [name, value] of Object.entries(componentProperties)) { 24 | $component.setAttribute(name, value); 25 | } 26 | $container.appendChild($component); 27 | 28 | const $contextButtons = document.querySelector('.context-buttons'); 29 | $contextButtons.addEventListener('click', (e) => { 30 | const button = e.target; 31 | if (!button.matches('button')) { 32 | return; 33 | } 34 | $container.context = JSON.parse(button.dataset.context); 35 | }); 36 | -------------------------------------------------------------------------------- /docs/adr/adr-0001-why-do-we-wrap-button-clicks.md: -------------------------------------------------------------------------------- 1 | --- 2 | kind: '📌 Architecture Decision Records' 3 | --- 4 | 5 | # ADR 0001: Why do we wrap `