Skip to content

Commit

Permalink
NEXT-38863 - implement new text editor component (#377)
Browse files Browse the repository at this point in the history
* NEXT-38863 - implement new text editor component

* Refactor translations to native i18n plugin

* NEXT-38863 - fix pipeline jobs

* Apply code formatting and fixable ESLint issues

* Apply code formatting and fixable ESLint issues

* Apply code formatting and fixable ESLint issues

* NEXT-38863 - add properties disabled, placeholder, label and error

* Apply code formatting and fixable ESLint issues

* NEXT-38863 - update snapshots and changelog

---------

Co-authored-by: jleifeld <[email protected]>
  • Loading branch information
jleifeld and jleifeld authored Jan 7, 2025
1 parent 1544b64 commit b3039c1
Show file tree
Hide file tree
Showing 34 changed files with 4,455 additions and 60 deletions.
11 changes: 11 additions & 0 deletions .changeset/wise-melons-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@shopware-ag/meteor-component-library": major
---

# Add new Text Editor component

This change introduces a new Text Editor component to the Meteor Component Library.

# Updated i18n configuration

We change the 'legacy' mode of i18n to 'false' in the Meteor Component Library configuration to use the new i18n composable.
1 change: 1 addition & 0 deletions packages/component-library/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import "@shopware-ag/meteor-tokens/administration/dark.css";

const i18n = createI18n({
// something vue-i18n options here ...
legacy: false,
globalInjection: true,
locale: "en",
fallbackLocale: "en",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 24 additions & 3 deletions packages/component-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,46 @@
"test:storybook": "test-storybook"
},
"dependencies": {
"@codemirror/lang-html": "^6.4.9",
"@floating-ui/dom": "^1.4.3",
"@floating-ui/vue": "^1.1.5",
"@shopware-ag/meteor-icon-kit": "workspace:*",
"@shopware-ag/meteor-tokens": "workspace:*",
"@storybook/addon-a11y": "^8.4.5",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/vue": "^8.1.0",
"@tiptap/extension-bubble-menu": "^2.10.0",
"@tiptap/extension-bullet-list": "^2.10.0",
"@tiptap/extension-character-count": "^2.10.0",
"@tiptap/extension-color": "^2.9.1",
"@tiptap/extension-highlight": "^2.10.3",
"@tiptap/extension-link": "^2.10.0",
"@tiptap/extension-list-item": "^2.10.0",
"@tiptap/extension-ordered-list": "^2.10.0",
"@tiptap/extension-placeholder": "^2.10.4",
"@tiptap/extension-subscript": "^2.9.1",
"@tiptap/extension-superscript": "^2.9.1",
"@tiptap/extension-table": "^2.10.3",
"@tiptap/extension-table-cell": "^2.10.3",
"@tiptap/extension-table-header": "^2.10.3",
"@tiptap/extension-table-row": "^2.10.3",
"@tiptap/extension-text-align": "^2.9.1",
"@tiptap/extension-text-style": "^2.9.1",
"@tiptap/extension-underline": "^2.9.1",
"@tiptap/pm": "^2.9.1",
"@tiptap/starter-kit": "^2.9.1",
"@tiptap/vue-3": "^2.9.1",
"@vuepic/vue-datepicker": "^10.0.0",
"@vueuse/components": "^10.7.2",
"@vueuse/core": "^10.7.2",
"codemirror": "^6.0.1",
"date-fns": "^2.30.0",
"date-fns-tz": "^2.0.0",
"focus-trap": "^7.5.4",
"inter-ui": "^3.19.3",
"lodash-es": "^4.17.21",
"nanoid": "^5.0.7",
"vue-codemirror6": "^1.3.8",
"vue-i18n": "^9.9.1",
"vue-smooth-reflow": "^0.1.12"
},
Expand Down Expand Up @@ -109,8 +133,5 @@
"vite-plugin-svgstring": "^1.0.0",
"vitest": "^1.1.3",
"vue-tsc": "^2.0.21"
},
"peerDependencies": {
"vue": ">= 3.5.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ $mt-field-transition:
margin-bottom: var(--scale-size-12);
}
&.is--disabled {
cursor: not-allowed;
}
&__hint-wrapper {
display: flex;
justify-content: space-between;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ const isInsideTooltip = useIsInsideTooltip();
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.mt-button--x-small {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { within, userEvent, fireEvent } from "@storybook/test";
import { expect } from "@storybook/test";

import meta, { type MtColorpickerMeta, type MtColorpickerStory } from "./mt-colorpicker.stories";
import { waitUntil } from "@/_internal/test-helper";

export default {
...meta,
Expand Down Expand Up @@ -56,6 +57,188 @@ export const VisualTestOpenColorpicker: MtColorpickerStory = {
},
};

export const VisualTestOpenColorpickerWithApplyMode: MtColorpickerStory = {
name: "Open colorpicker with apply mode",
args: {
modelValue: "rgba(72, 228, 37, 0.81)",
applyMode: true,
colorOutput: "rgb",
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

const pickerToggle = canvas.getByLabelText("colorpicker-toggle");

await userEvent.click(pickerToggle);

// Look inside the popover
const popover = within(
document.getElementsByClassName("mt-floating-ui__content")[0] as HTMLElement,
);

const colorRange = popover.getByLabelText("colorpicker-color-range") as HTMLInputElement;
const alphaRange = popover.getByLabelText("colorpicker-alpha-range") as HTMLInputElement;
const hexInput = popover.getByLabelText("hex-value") as HTMLInputElement;
const redInput = popover.getByLabelText("red-value") as HTMLInputElement;
const greenInput = popover.getByLabelText("green-value") as HTMLInputElement;
const blueInput = popover.getByLabelText("blue-value") as HTMLInputElement;
const alphaInput = popover.getByLabelText("alpha-value") as HTMLInputElement;

expect(colorRange).toBeDefined();
expect(colorRange.value).toEqual("109");
expect(alphaRange).toBeDefined();
expect(alphaRange.value).toEqual("0.81");

expect(hexInput).toBeDefined();
expect(hexInput.value).toEqual("#48e425cf");
expect(redInput).toBeDefined();
expect(redInput.value).toEqual("72");
expect(greenInput).toBeDefined();
expect(greenInput.value).toEqual("228");
expect(blueInput).toBeDefined();
expect(blueInput.value).toEqual("37");
expect(alphaInput).toBeDefined();
expect(alphaInput.value).toEqual("81");

// Check for apply button
const applyButton = popover.getByLabelText("colorpicker-apply-color") as HTMLButtonElement;
expect(applyButton).toBeDefined();
},
};

export const TestOpenColorpickerWithApplyMode: MtColorpickerStory = {
name: "Use colorpicker with apply mode",
args: {
modelValue: "rgba(72, 228, 37, 0.81)",
applyMode: true,
colorOutput: "rgb",
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

const pickerToggle = canvas.getByLabelText("colorpicker-toggle");

await userEvent.click(pickerToggle);

// Look inside the popover
const popover = within(
document.getElementsByClassName("mt-floating-ui__content")[0] as HTMLElement,
);

const colorRange = popover.getByLabelText("colorpicker-color-range") as HTMLInputElement;
const alphaRange = popover.getByLabelText("colorpicker-alpha-range") as HTMLInputElement;
const hexInput = popover.getByLabelText("hex-value") as HTMLInputElement;
const redInput = popover.getByLabelText("red-value") as HTMLInputElement;
const greenInput = popover.getByLabelText("green-value") as HTMLInputElement;
const blueInput = popover.getByLabelText("blue-value") as HTMLInputElement;
const alphaInput = popover.getByLabelText("alpha-value") as HTMLInputElement;

expect(colorRange).toBeDefined();
expect(colorRange.value).toEqual("109");
expect(alphaRange).toBeDefined();
expect(alphaRange.value).toEqual("0.81");

expect(hexInput).toBeDefined();
expect(hexInput.value).toEqual("#48e425cf");
expect(redInput).toBeDefined();
expect(redInput.value).toEqual("72");
expect(greenInput).toBeDefined();
expect(greenInput.value).toEqual("228");
expect(blueInput).toBeDefined();
expect(blueInput.value).toEqual("37");
expect(alphaInput).toBeDefined();
expect(alphaInput.value).toEqual("81");

// Check for apply button
const applyButton = popover.getByLabelText("colorpicker-apply-color") as HTMLButtonElement;
expect(applyButton).toBeDefined();

// Change colors
fireEvent.input(colorRange, { target: { value: 300 } });
fireEvent.input(alphaRange, { target: { value: 0.5 } });

// Apply changes
await userEvent.click(applyButton);

// Wait until the popover is closed
await waitUntil(() => {
return document.getElementsByClassName("mt-floating-ui__content").length === 0;
});

// Check if the color is applied
expect(args.updateModelValue).toHaveBeenCalledWith("rgba(228, 37, 228, 0.5)");
},
};

export const ResetsColorInApplyMode: MtColorpickerStory = {
name: "Resets color in apply mode when closed without applying",
args: {
modelValue: "rgba(72, 228, 37, 0.81)",
applyMode: true,
colorOutput: "rgb",
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);

const pickerToggle = canvas.getByLabelText("colorpicker-toggle");

await userEvent.click(pickerToggle);

// Look inside the popover
const popover = within(
document.getElementsByClassName("mt-floating-ui__content")[0] as HTMLElement,
);

const colorRange = popover.getByLabelText("colorpicker-color-range") as HTMLInputElement;
const alphaRange = popover.getByLabelText("colorpicker-alpha-range") as HTMLInputElement;
const hexInput = popover.getByLabelText("hex-value") as HTMLInputElement;
const redInput = popover.getByLabelText("red-value") as HTMLInputElement;
const greenInput = popover.getByLabelText("green-value") as HTMLInputElement;
const blueInput = popover.getByLabelText("blue-value") as HTMLInputElement;
const alphaInput = popover.getByLabelText("alpha-value") as HTMLInputElement;

expect(colorRange).toBeDefined();
expect(colorRange.value).toEqual("109");
expect(alphaRange).toBeDefined();
expect(alphaRange.value).toEqual("0.81");

expect(hexInput).toBeDefined();
expect(hexInput.value).toEqual("#48e425cf");
expect(redInput).toBeDefined();
expect(redInput.value).toEqual("72");
expect(greenInput).toBeDefined();
expect(greenInput.value).toEqual("228");
expect(blueInput).toBeDefined();
expect(blueInput.value).toEqual("37");
expect(alphaInput).toBeDefined();
expect(alphaInput.value).toEqual("81");

// Check for apply button
const applyButton = popover.getByLabelText("colorpicker-apply-color") as HTMLButtonElement;
expect(applyButton).toBeDefined();

// Change colors
fireEvent.input(colorRange, { target: { value: 300 } });
fireEvent.input(alphaRange, { target: { value: 0.5 } });

const colorpickerInputField = canvas.getByLabelText(
"colorpicker-color-value",
) as HTMLInputElement;

// Close popover without applying
await userEvent.click(colorpickerInputField);

// Wait until the popover is closed
await waitUntil(() => {
return document.getElementsByClassName("mt-floating-ui__content").length === 0;
});

// Check if the color is resetted
expect(args.updateModelValue).not.toHaveBeenCalled();
expect(colorpickerInputField.value).toEqual("rgba(72, 228, 37, 0.81)");
},
};

export const VisualTestChangeColorpickerColor: MtColorpickerStory = {
name: "Change colorpicker color",
args: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import MtColorpicker from "./mt-colorpicker.vue";
import type { StoryObj } from "@storybook/vue3";
import type { SlottedMeta } from "@/_internal/story-helper";
import { ref } from "vue";
import { fn } from "@storybook/test";

export type MtColorpickerMeta = SlottedMeta<typeof MtColorpicker, "default">;
export type MtColorpickerMeta = SlottedMeta<typeof MtColorpicker, "default" | "updateModelValue">;

export default {
title: "Components/Form/mt-colorpicker",
component: MtColorpicker,
render: (args) => ({
components: { MtColorpicker },
template: '<mt-colorpicker v-bind="args"></mt-colorpicker>',
template: `<mt-colorpicker
v-bind="args"
:modelValue="currentModelValue"
@update:modelValue="onUpdateModelValue"
></mt-colorpicker>`,
setup: () => {
const currentModelValue = ref(args.modelValue);
const onUpdateModelValue = (value: string) => {
currentModelValue.value = value;
args.updateModelValue(value);
};

return {
args,
currentModelValue,
onUpdateModelValue,
};
},
}),
Expand All @@ -30,6 +44,8 @@ export default {
isInherited: false,
isInheritanceField: false,
disableInheritanceToggle: false,
compact: false,
updateModelValue: fn(),
},
} as MtColorpickerMeta;

Expand Down
Loading

0 comments on commit b3039c1

Please sign in to comment.