mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
feat(editor): Add color picker design system component (#6179)
* feat(editor): Add color picker design system component * fix(editor): remove type imports * fix(editor): fix v-model * fix(editor): fix props * fix(editor): color picker view model * test(editor): add some basic test to color picker * fix(editor): update color picker styles * fix(editor): color picker view model * test(editor): update snapshot
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import type { StoryFn } from '@storybook/vue';
|
||||
import N8nColorPicker from './ColorPicker.vue';
|
||||
|
||||
export default {
|
||||
title: 'Atoms/ColorPicker',
|
||||
component: N8nColorPicker,
|
||||
argTypes: {
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
},
|
||||
size: {
|
||||
control: 'select',
|
||||
options: ['mini', 'small', 'medium', 'large'],
|
||||
},
|
||||
showAlpha: {
|
||||
control: 'boolean',
|
||||
},
|
||||
colorFormat: {
|
||||
control: 'select',
|
||||
options: ['hsl', 'hsv', 'hex', 'rgb'],
|
||||
},
|
||||
popperClass: {
|
||||
control: 'text',
|
||||
},
|
||||
predefine: {
|
||||
control: 'array',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const methods = {
|
||||
onChange: action('change'),
|
||||
onActiveChange: action('active-change'),
|
||||
onInput: action('input'),
|
||||
};
|
||||
|
||||
const DefaultTemplate: StoryFn = (args, { argTypes }) => ({
|
||||
props: Object.keys(argTypes),
|
||||
components: {
|
||||
N8nColorPicker,
|
||||
},
|
||||
data: () => ({
|
||||
color: null,
|
||||
}),
|
||||
template:
|
||||
'<n8n-color-picker v-model="color" v-bind="$props" @input="onInput" @change="onChange" @active-change="onActiveChange" />',
|
||||
methods,
|
||||
});
|
||||
|
||||
export const Default = DefaultTemplate.bind({});
|
||||
Default.args = {
|
||||
disabled: false,
|
||||
size: 'medium',
|
||||
showAlpha: false,
|
||||
colorFormat: '',
|
||||
popperClass: '',
|
||||
showInput: true,
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { ColorPicker } from 'element-ui';
|
||||
import N8nInput from '../N8nInput';
|
||||
|
||||
export type Props = {
|
||||
disabled?: boolean;
|
||||
size?: 'small' | 'medium' | 'mini';
|
||||
showAlpha?: boolean;
|
||||
colorFormat?: 'hex' | 'rgb' | 'hsl' | 'hsv';
|
||||
popperClass?: string;
|
||||
predefine?: string[];
|
||||
value?: string;
|
||||
showInput?: boolean;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
disabled: false,
|
||||
size: 'medium',
|
||||
showAlpha: false,
|
||||
colorFormat: 'hex',
|
||||
popperClass: '',
|
||||
showInput: true,
|
||||
value: null,
|
||||
});
|
||||
|
||||
const color = ref(props.value);
|
||||
|
||||
const colorPickerProps = computed(() => {
|
||||
const { value, showInput, ...rest } = props;
|
||||
return rest;
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'input', value: string): void;
|
||||
(event: 'change', value: string): void;
|
||||
(event: 'active-change', value: string): void;
|
||||
}>();
|
||||
|
||||
const model = computed({
|
||||
get() {
|
||||
return color.value;
|
||||
},
|
||||
set(value: string) {
|
||||
color.value = value;
|
||||
emit('input', value);
|
||||
},
|
||||
});
|
||||
|
||||
const onChange = (value: string) => {
|
||||
emit('change', value);
|
||||
};
|
||||
|
||||
const onInput = (value: string) => {
|
||||
color.value = value;
|
||||
};
|
||||
|
||||
const onActiveChange = (value: string) => {
|
||||
emit('active-change', value);
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<span :class="['n8n-color-picker', $style.component]">
|
||||
<color-picker
|
||||
v-model="model"
|
||||
v-bind="colorPickerProps"
|
||||
@change="onChange"
|
||||
@active-change="onActiveChange"
|
||||
/>
|
||||
<n8n-input
|
||||
v-if="showInput"
|
||||
:class="$style.input"
|
||||
:disabled="props.disabled"
|
||||
:size="props.size"
|
||||
:value="color"
|
||||
@input="onInput"
|
||||
type="text"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
<style lang="scss" module>
|
||||
.component {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
margin-left: var(--spacing-3xs);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-color-picker) {
|
||||
.el-color-picker__empty,
|
||||
.el-color-picker__icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,16 @@
|
||||
import { render } from '@testing-library/vue';
|
||||
import N8nColorPicker from '../ColorPicker.vue';
|
||||
|
||||
describe('components', () => {
|
||||
describe('N8nColorPicker', () => {
|
||||
it('should render with input', () => {
|
||||
const { container } = render(N8nColorPicker);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render without input', () => {
|
||||
const { container } = render(N8nColorPicker, { props: { showInput: false } });
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,269 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`components > N8nColorPicker > should render with input 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="n8n-color-picker component"
|
||||
data-v-dab78bb8=""
|
||||
>
|
||||
<div
|
||||
class="el-color-picker el-color-picker--medium"
|
||||
data-v-dab78bb8=""
|
||||
>
|
||||
<!---->
|
||||
<div
|
||||
class="el-color-picker__trigger"
|
||||
>
|
||||
<span
|
||||
class="el-color-picker__color"
|
||||
>
|
||||
<span
|
||||
class="el-color-picker__color-inner"
|
||||
style="background-color: transparent;"
|
||||
/>
|
||||
<span
|
||||
class="el-color-picker__empty el-icon-close"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="el-color-picker__icon el-icon-arrow-down"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
<transition-stub
|
||||
class="el-color-picker__panel"
|
||||
name="el-zoom-in-top"
|
||||
>
|
||||
<div
|
||||
class="el-color-dropdown"
|
||||
style="display: none;"
|
||||
>
|
||||
<div
|
||||
class="el-color-dropdown__main-wrapper"
|
||||
>
|
||||
<div
|
||||
class="el-color-hue-slider is-vertical"
|
||||
style="float: right;"
|
||||
>
|
||||
<div
|
||||
class="el-color-hue-slider__bar"
|
||||
/>
|
||||
<div
|
||||
class="el-color-hue-slider__thumb"
|
||||
style="left: 0px; top: 0px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="el-color-svpanel"
|
||||
style="background-color: rgb(255, 0, 0);"
|
||||
>
|
||||
<div
|
||||
class="el-color-svpanel__white"
|
||||
/>
|
||||
<div
|
||||
class="el-color-svpanel__black"
|
||||
/>
|
||||
<div
|
||||
class="el-color-svpanel__cursor"
|
||||
style="top: 0px; left: 0px;"
|
||||
>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<div
|
||||
class="el-color-dropdown__btns"
|
||||
>
|
||||
<span
|
||||
class="el-color-dropdown__value"
|
||||
>
|
||||
<div
|
||||
class="el-input el-input--mini"
|
||||
>
|
||||
<!---->
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="el-input__inner"
|
||||
type="text"
|
||||
/>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
</span>
|
||||
<button
|
||||
class="el-button el-color-dropdown__link-btn el-button--text el-button--mini"
|
||||
type="button"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<span>
|
||||
|
||||
清空
|
||||
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="el-button el-color-dropdown__btn el-button--default el-button--mini is-plain"
|
||||
type="button"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<span>
|
||||
|
||||
确定
|
||||
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
<div
|
||||
class="el-input el-input--medium n8n-input input"
|
||||
data-v-dab78bb8=""
|
||||
>
|
||||
<!---->
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="el-input__inner"
|
||||
type="text"
|
||||
/>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components > N8nColorPicker > should render without input 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="n8n-color-picker component"
|
||||
data-v-dab78bb8=""
|
||||
>
|
||||
<div
|
||||
class="el-color-picker el-color-picker--medium"
|
||||
data-v-dab78bb8=""
|
||||
>
|
||||
<!---->
|
||||
<div
|
||||
class="el-color-picker__trigger"
|
||||
>
|
||||
<span
|
||||
class="el-color-picker__color"
|
||||
>
|
||||
<span
|
||||
class="el-color-picker__color-inner"
|
||||
style="background-color: transparent;"
|
||||
/>
|
||||
<span
|
||||
class="el-color-picker__empty el-icon-close"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="el-color-picker__icon el-icon-arrow-down"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
<transition-stub
|
||||
class="el-color-picker__panel"
|
||||
name="el-zoom-in-top"
|
||||
>
|
||||
<div
|
||||
class="el-color-dropdown"
|
||||
style="display: none;"
|
||||
>
|
||||
<div
|
||||
class="el-color-dropdown__main-wrapper"
|
||||
>
|
||||
<div
|
||||
class="el-color-hue-slider is-vertical"
|
||||
style="float: right;"
|
||||
>
|
||||
<div
|
||||
class="el-color-hue-slider__bar"
|
||||
/>
|
||||
<div
|
||||
class="el-color-hue-slider__thumb"
|
||||
style="left: 0px; top: 0px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="el-color-svpanel"
|
||||
style="background-color: rgb(255, 0, 0);"
|
||||
>
|
||||
<div
|
||||
class="el-color-svpanel__white"
|
||||
/>
|
||||
<div
|
||||
class="el-color-svpanel__black"
|
||||
/>
|
||||
<div
|
||||
class="el-color-svpanel__cursor"
|
||||
style="top: 0px; left: 0px;"
|
||||
>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
<div
|
||||
class="el-color-dropdown__btns"
|
||||
>
|
||||
<span
|
||||
class="el-color-dropdown__value"
|
||||
>
|
||||
<div
|
||||
class="el-input el-input--mini"
|
||||
>
|
||||
<!---->
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="el-input__inner"
|
||||
type="text"
|
||||
/>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
</span>
|
||||
<button
|
||||
class="el-button el-color-dropdown__link-btn el-button--text el-button--mini"
|
||||
type="button"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<span>
|
||||
|
||||
清空
|
||||
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="el-button el-color-dropdown__btn el-button--default el-button--mini is-plain"
|
||||
type="button"
|
||||
>
|
||||
<!---->
|
||||
<!---->
|
||||
<span>
|
||||
|
||||
确定
|
||||
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition-stub>
|
||||
</div>
|
||||
<!---->
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,3 @@
|
||||
import N8nColorPicker from './ColorPicker.vue';
|
||||
|
||||
export default N8nColorPicker;
|
||||
@@ -48,3 +48,4 @@ export { default as N8nUsersList } from './N8nUsersList';
|
||||
export { default as N8nResizeWrapper } from './N8nResizeWrapper';
|
||||
export { default as N8nRecycleScroller } from './N8nRecycleScroller';
|
||||
export { default as N8nCheckbox } from './N8nCheckbox';
|
||||
export { default as N8nColorPicker } from './N8nColorPicker';
|
||||
|
||||
@@ -51,6 +51,7 @@ import {
|
||||
N8nResizeWrapper,
|
||||
N8nRecycleScroller,
|
||||
N8nCheckbox,
|
||||
N8nColorPicker,
|
||||
} from './components';
|
||||
|
||||
export const N8nPlugin: PluginObject<{}> = {
|
||||
@@ -105,5 +106,6 @@ export const N8nPlugin: PluginObject<{}> = {
|
||||
app.component('n8n-resize-wrapper', N8nResizeWrapper);
|
||||
app.component('n8n-recycle-scroller', N8nRecycleScroller);
|
||||
app.component('n8n-checkbox', N8nCheckbox);
|
||||
app.component('n8n-color-picker', N8nColorPicker);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user