mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-25 07:47:55 +01:00
Storybook.
This commit is contained in:
parent
b806e58e55
commit
51c442d122
21
packages/mindplot/.storybook/main.js
Normal file
21
packages/mindplot/.storybook/main.js
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
"stories": [
|
||||
"../storybook/src/**/*.stories.mdx",
|
||||
"../storybook/src/**/*.stories.@(js|jsx|ts|tsx)"
|
||||
],
|
||||
"addons": [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions"
|
||||
],
|
||||
"framework": "@storybook/html",
|
||||
typescript: {
|
||||
check: false,
|
||||
checkOptions: {},
|
||||
reactDocgen: 'react-docgen-typescript',
|
||||
reactDocgenTypescriptOptions: {
|
||||
shouldExtractLiteralValuesFromEnum: true,
|
||||
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
|
||||
},
|
||||
},
|
||||
};
|
9
packages/mindplot/.storybook/preview.js
Normal file
9
packages/mindplot/.storybook/preview.js
Normal file
@ -0,0 +1,9 @@
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
}
|
@ -29,7 +29,9 @@
|
||||
"cy:open": "cypress open",
|
||||
"test:unit": "jest ./test/unit/export/*.ts ./test/unit/import/*.ts ./test/unit/layout/*.js --verbose --silent --detectOpenHandles",
|
||||
"test:integration": "start-server-and-test playground http-get://localhost:8083 cy:run",
|
||||
"test": "yarn test:unit && yarn test:integration"
|
||||
"test": "yarn test:unit && yarn test:integration",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/jquery": "^3.5.11",
|
||||
@ -41,6 +43,18 @@
|
||||
"xml-formatter": "^2.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@storybook/addon-actions": "^6.5.16",
|
||||
"@storybook/addon-docs": "^6.5.16",
|
||||
"@storybook/addon-essentials": "^6.5.16",
|
||||
"@storybook/addon-interactions": "^6.5.16",
|
||||
"@storybook/addon-links": "^6.5.16",
|
||||
"@storybook/builder-webpack4": "^6.5.16",
|
||||
"@storybook/html": "^6.5.16",
|
||||
"@storybook/manager-webpack4": "^6.5.16",
|
||||
"@storybook/testing-library": "^0.0.13",
|
||||
"babel-loader": "^8.3.0",
|
||||
"blob-polyfill": "^6.0.20211015",
|
||||
"cypress": "^12.3.0",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
|
@ -15,6 +15,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import Point from '@wisemapping/web2d';
|
||||
import Messages, { $msg } from './Messages';
|
||||
@ -78,22 +80,19 @@ class Designer extends Events {
|
||||
|
||||
private _cleanScreen!: () => void;
|
||||
|
||||
constructor(options: DesignerOptions, divElement: JQuery) {
|
||||
constructor(options: DesignerOptions) {
|
||||
super();
|
||||
$assert(options, 'options must be defined');
|
||||
$assert(options.zoom, 'zoom must be defined');
|
||||
$assert(divElement, 'divElement must be defined');
|
||||
|
||||
// Set up i18n location ...
|
||||
console.log(`Editor location: ${options.locale}`);
|
||||
Messages.init(options.locale ? options.locale : 'en');
|
||||
const divElem = options.divContainer;
|
||||
|
||||
this._options = options;
|
||||
|
||||
// Set full div elem render area.The component must fill container size
|
||||
// container is responsible for location and size
|
||||
divElement.css('width', '100%');
|
||||
divElement.css('height', '100%');
|
||||
$(divElem).css('width', '100%');
|
||||
$(divElem).css('height', '100%');
|
||||
|
||||
// Dispatcher manager ...
|
||||
const commandContext = new CommandContext(this);
|
||||
@ -108,7 +107,7 @@ class Designer extends Events {
|
||||
this._model = new DesignerModel(options);
|
||||
|
||||
// Init Screen manager..
|
||||
const screenManager = new ScreenManager(divElement);
|
||||
const screenManager = new ScreenManager(divElem);
|
||||
this._workspace = new Workspace(screenManager, this._model.getZoom(), this.isReadOnly());
|
||||
|
||||
// Init layout manager ...
|
||||
|
@ -16,7 +16,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import $ from 'jquery';
|
||||
import PersistenceManager from './PersistenceManager';
|
||||
import Designer from './Designer';
|
||||
import { DesignerOptions } from './DesignerOptionsBuilder';
|
||||
@ -26,14 +25,14 @@ import ReadOnlyWidgetManager from './ReadOnlyWidgetManager';
|
||||
let designer: Designer;
|
||||
|
||||
export function buildDesigner(options: DesignerOptions): Designer {
|
||||
const divContainer = options.divContainer ? $(options.divContainer) : $(`#${options.container}`);
|
||||
$assert(divContainer, 'container could not be null');
|
||||
const containerElem = options.divContainer;
|
||||
$assert(containerElem, 'container could not be null');
|
||||
if (designer) {
|
||||
throw new Error('Designer can does not support multiple initializations');
|
||||
}
|
||||
|
||||
// Register load events ...
|
||||
designer = new Designer(options, divContainer);
|
||||
designer = new Designer(options);
|
||||
|
||||
// Configure default persistence manager ...
|
||||
const persistence = options.persistenceManager;
|
||||
|
@ -25,7 +25,6 @@ export type DesignerOptions = {
|
||||
mode: EditorRenderMode;
|
||||
mapId?: string;
|
||||
divContainer: HTMLElement;
|
||||
container: string;
|
||||
persistenceManager?: PersistenceManager;
|
||||
widgetManager?: WidgetManager;
|
||||
saveOnLoad?: boolean;
|
||||
@ -40,7 +39,6 @@ class OptionsBuilder {
|
||||
mode: 'edition-owner',
|
||||
zoom: 0.85,
|
||||
saveOnLoad: true,
|
||||
container: 'mindplot',
|
||||
locale: 'en',
|
||||
};
|
||||
|
||||
|
@ -45,12 +45,14 @@ class LinkIcon extends ImageIcon {
|
||||
private _registerEvents() {
|
||||
this.getElement().setCursor('pointer');
|
||||
|
||||
if (WidgetManager.isInitialized()) {
|
||||
const manager = WidgetManager.getInstance();
|
||||
manager.createTooltipForLink(this._topic, this._linksModel as LinkModel, this);
|
||||
if (!this._readOnly) {
|
||||
manager.configureEditorForLink(this._topic, this._linksModel as LinkModel, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): FeatureModel {
|
||||
return this._linksModel;
|
||||
|
@ -28,13 +28,6 @@ import { $msg } from './Messages';
|
||||
import DesignerKeyboard from './DesignerKeyboard';
|
||||
import LocalStorageManager from './LocalStorageManager';
|
||||
|
||||
export type MindplotWebComponentInterface = {
|
||||
id: string;
|
||||
mode: string;
|
||||
ref: object;
|
||||
locale?: string;
|
||||
zoom?: number;
|
||||
};
|
||||
/**
|
||||
* WebComponent implementation for minplot designer.
|
||||
* This component is registered as mindplot-component in customElements api. (see https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define)
|
||||
@ -59,7 +52,7 @@ class MindplotWebComponent extends HTMLElement {
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.setAttribute('class', 'wise-editor');
|
||||
wrapper.setAttribute('id', 'mindplot');
|
||||
wrapper.setAttribute('id', 'mindplot-div-container');
|
||||
|
||||
this._shadowRoot.appendChild(wrapper);
|
||||
this._isLoaded = false;
|
||||
@ -87,7 +80,7 @@ class MindplotWebComponent extends HTMLElement {
|
||||
const persistenceManager = persistence || new LocalStorageManager('map.xml', false, false);
|
||||
const mode = editorRenderMode || 'viewonly';
|
||||
|
||||
const mindplodElem = this._shadowRoot.getElementById('mindplot');
|
||||
const mindplodElem = this._shadowRoot.getElementById('mindplot-div-container');
|
||||
$assert(mindplodElem, 'Root mindplot element could not be loaded');
|
||||
|
||||
const options = DesignerOptionsBuilder.buildOptions({
|
||||
@ -95,7 +88,6 @@ class MindplotWebComponent extends HTMLElement {
|
||||
mode,
|
||||
widgetManager,
|
||||
divContainer: mindplodElem!,
|
||||
container: 'mindplot',
|
||||
zoom: zoom ? Number.parseFloat(zoom) : 1,
|
||||
locale: locale || 'en',
|
||||
});
|
||||
|
@ -0,0 +1,9 @@
|
||||
type MindplotWebComponentInterface = {
|
||||
id: string;
|
||||
mode: string;
|
||||
ref: object;
|
||||
locale?: string;
|
||||
zoom?: number;
|
||||
};
|
||||
|
||||
export default MindplotWebComponentInterface;
|
@ -44,12 +44,14 @@ class NoteIcon extends ImageIcon {
|
||||
private _registerEvents(): void {
|
||||
this.getElement().setCursor('pointer');
|
||||
|
||||
if (WidgetManager.isInitialized()) {
|
||||
const manager = WidgetManager.getInstance();
|
||||
manager.createTooltipForNote(this._topic, this._linksModel as NoteModel, this);
|
||||
if (!this._readOnly) {
|
||||
manager.configureEditorForNote(this._topic, this._linksModel as NoteModel, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): FeatureModel {
|
||||
return this._linksModel;
|
||||
|
@ -26,7 +26,7 @@ import registerTouchHandler from '../../../../libraries/jquery.touchevent';
|
||||
registerTouchHandler($);
|
||||
|
||||
class ScreenManager {
|
||||
private _divContainer: JQuery;
|
||||
private _divContainer: JQuery<HTMLDivElement>;
|
||||
|
||||
private _padding: { x: number; y: number };
|
||||
|
||||
@ -34,9 +34,9 @@ class ScreenManager {
|
||||
|
||||
private _scale: number;
|
||||
|
||||
constructor(divElement: JQuery) {
|
||||
constructor(divElement: HTMLElement) {
|
||||
$assert(divElement, 'can not be null');
|
||||
this._divContainer = divElement;
|
||||
this._divContainer = $(divElement) as JQuery<HTMLDivElement>;
|
||||
this._padding = { x: 0, y: 0 };
|
||||
|
||||
// Ignore default click event propagation. Prevent 'click' event on drag.
|
||||
@ -56,12 +56,12 @@ class ScreenManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current visibile area in the browser.
|
||||
* Return the current visible area in the browser.
|
||||
*/
|
||||
getVisibleBrowserSize(): { width: number; height: number } {
|
||||
return {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight - Number.parseInt(this._divContainer.css('top'), 10),
|
||||
height: window.innerHeight,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1206,7 @@ abstract class Topic extends NodeGraph {
|
||||
textShape.setFontName(fontFamily);
|
||||
|
||||
const text = this.getText();
|
||||
textShape.setText(text);
|
||||
textShape.setText(text.trim());
|
||||
|
||||
// Calculate topic size and adjust elements ...
|
||||
const textWidth = textShape.getWidth();
|
||||
|
@ -20,7 +20,7 @@ const CONNECTOR_WIDTH = 6;
|
||||
|
||||
const OUTER_SHAPE_ATTRIBUTES = {
|
||||
fillColor: 'rgb(252,235,192)',
|
||||
stroke: '1 dot rgb(241,163,39)',
|
||||
stroke: '1 solid rgb(241,163,39)',
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
@ -15,9 +15,16 @@ abstract class WidgetManager {
|
||||
};
|
||||
|
||||
static getInstance(): WidgetManager {
|
||||
if (!this._instance) {
|
||||
throw new Error('WidgetManager has not been initialized');
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
static isInitialized() {
|
||||
return this._instance !== undefined;
|
||||
}
|
||||
|
||||
private createTooltip(
|
||||
mindmapElement,
|
||||
title: string,
|
||||
|
@ -140,7 +140,7 @@ abstract class INodeModel {
|
||||
return this.getProperty('shapeType') as TopicShapeType;
|
||||
}
|
||||
|
||||
setShapeType(type: string) {
|
||||
setShapeType(type: TopicShapeType | undefined) {
|
||||
this.putProperty('shapeType', type);
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ abstract class INodeModel {
|
||||
return this.getProperty('order') as number;
|
||||
}
|
||||
|
||||
setFontFamily(fontFamily: string): void {
|
||||
setFontFamily(fontFamily: string | undefined): void {
|
||||
this.putProperty('fontFamily', fontFamily);
|
||||
}
|
||||
|
||||
@ -188,7 +188,7 @@ abstract class INodeModel {
|
||||
return this.getProperty('fontColor') as string;
|
||||
}
|
||||
|
||||
setFontSize(size: number): void {
|
||||
setFontSize(size: number | undefined): void {
|
||||
this.putProperty('fontSize', size);
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import emojiToIconMap from './iconToEmoji.json';
|
||||
import { LineType } from '../ConnectionLine';
|
||||
import { FontWeightType } from '../FontWeightType';
|
||||
import { FontStyleType } from '../FontStyleType';
|
||||
import { TopicShapeType } from '../model/INodeModel';
|
||||
|
||||
class XMLSerializerTango implements XMLMindmapSerializer {
|
||||
private static MAP_ROOT_NODE = 'map';
|
||||
@ -335,7 +336,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
|
||||
if (shape) {
|
||||
// Fix typo on serialization....
|
||||
shape = shape.replace('rectagle', 'rectangle');
|
||||
topic.setShapeType(shape);
|
||||
topic.setShapeType(shape as TopicShapeType);
|
||||
|
||||
// Is an image ?
|
||||
const image = domElem.getAttribute('image');
|
||||
|
@ -30,14 +30,13 @@ import TextImporterFactory from './components/import/TextImporterFactory';
|
||||
import Exporter from './components/export/Exporter';
|
||||
import Importer from './components/import/Importer';
|
||||
import DesignerKeyboard from './components/DesignerKeyboard';
|
||||
import EditorRenderMode from './components/EditorRenderMode';
|
||||
import type EditorRenderMode from './components/EditorRenderMode';
|
||||
import DesignerModel from './components/DesignerModel';
|
||||
|
||||
import SvgImageIcon from './components/SvgImageIcon';
|
||||
|
||||
import MindplotWebComponent, {
|
||||
MindplotWebComponentInterface,
|
||||
} from './components/MindplotWebComponent';
|
||||
import MindplotWebComponent from './components/MindplotWebComponent';
|
||||
import type MindplotWebComponentInterface from './components/MindplotWebComponentInterface';
|
||||
import LinkIcon from './components/LinkIcon';
|
||||
import NoteIcon from './components/NoteIcon';
|
||||
import Topic from './components/Topic';
|
||||
|
@ -20,8 +20,6 @@ import PersistenceManager from './components/PersistenceManager';
|
||||
import LocalStorageManager from './components/LocalStorageManager';
|
||||
import MindplotWebComponent from './components/MindplotWebComponent';
|
||||
|
||||
console.log('loading static mindmap in read-only');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const globalAny: any = global;
|
||||
globalAny.jQuery = jquery;
|
||||
|
78
packages/mindplot/storybook/src/stories/Topic.stories.ts
Normal file
78
packages/mindplot/storybook/src/stories/Topic.stories.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import createTopic from './Topic';
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/html/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: 'Mindplot/Topic',
|
||||
// More on argTypes: https://storybook.js.org/docs/html/api/argtypes
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
borderColor: { control: 'color' },
|
||||
fontFamily: {
|
||||
options: ['Arial', 'Verdana'],
|
||||
control: { type: 'select' },
|
||||
},
|
||||
fontSize: { control: { type: 'number', min: 0, max: 20, step: 2 } },
|
||||
fontColor: { control: 'color' },
|
||||
shapeType: {
|
||||
options: ['rectangle', 'rounded rectangle', 'elipse', 'line'],
|
||||
control: { type: 'select' },
|
||||
},
|
||||
text: { control: 'text' },
|
||||
noteText: { control: 'text' },
|
||||
linkText: { control: 'text' },
|
||||
eicon: { control: 'multi-select', options: ['❤️', '🌈', '🖇️'] },
|
||||
},
|
||||
};
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/html/writing-stories/introduction#using-args
|
||||
const Template = ({ ...args }) => createTopic({ ...args });
|
||||
|
||||
export const BoderderStyle = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
BoderderStyle.args = {
|
||||
text: 'Border Style',
|
||||
borderColor: 'red',
|
||||
};
|
||||
|
||||
export const FontStyle = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
FontStyle.args = {
|
||||
text: 'Font Style',
|
||||
fontColor: 'red',
|
||||
fontSize: 10,
|
||||
fontFamily: 'Fantasy',
|
||||
};
|
||||
|
||||
export const BackgroundColor = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
BackgroundColor.args = {
|
||||
text: 'Background Color Style',
|
||||
backgroundColor: 'red',
|
||||
};
|
||||
|
||||
export const NoteFeature = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
NoteFeature.args = {
|
||||
text: 'Note Feature',
|
||||
noteText: 'This is great note\nwith two lines',
|
||||
};
|
||||
|
||||
export const LinkFeature = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
LinkFeature.args = {
|
||||
text: 'Link Feature',
|
||||
linkText: 'https://www.google.com/',
|
||||
};
|
||||
|
||||
export const IconFeature = Template.bind({});
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
IconFeature.args = {
|
||||
text: 'EIcon Feature\n with multi-line',
|
||||
eicon: ['❤️', '🌈', '🖇️'],
|
||||
};
|
87
packages/mindplot/storybook/src/stories/Topic.ts
Normal file
87
packages/mindplot/storybook/src/stories/Topic.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
import { LinkModel, Mindmap, NoteModel, Topic } from '../../../src';
|
||||
import NodeModel from '../../../src/components/model/NodeModel';
|
||||
import CentralTopic from '../../../src/components/CentralTopic';
|
||||
import Workspace from '../../../src/components/Workspace';
|
||||
import ScreenManager from '../../../src/components/ScreenManager';
|
||||
import EmojiIconModel from '../../../src/components/model/EmojiIconModel';
|
||||
|
||||
const registerRefreshHook = (topic: Topic) => {
|
||||
// Trigger a redraw after the node is added ...
|
||||
if (globalThis.observer) {
|
||||
globalThis.observer.disconnect();
|
||||
}
|
||||
|
||||
globalThis.observer = new MutationObserver(() => {
|
||||
topic.redraw();
|
||||
console.log('Refresh triggered...');
|
||||
});
|
||||
globalThis.observer.observe(document.getElementById('root')!, { childList: true });
|
||||
};
|
||||
|
||||
const createTopic = ({
|
||||
backgroundColor = undefined,
|
||||
text = undefined,
|
||||
borderColor = undefined,
|
||||
shapeType = undefined,
|
||||
fontFamily = undefined,
|
||||
fontSize = undefined,
|
||||
fontColor = undefined,
|
||||
noteText = undefined,
|
||||
linkText = undefined,
|
||||
eicon = undefined,
|
||||
}) => {
|
||||
// Build basic container ...
|
||||
const divElem = document.createElement('div');
|
||||
const jqueryDiv = $(divElem);
|
||||
jqueryDiv.css({
|
||||
height: '600px',
|
||||
width: '800px',
|
||||
backgroundColor: 'gray',
|
||||
});
|
||||
|
||||
// Initialize designer helpers ...
|
||||
const screenManager = new ScreenManager(divElem);
|
||||
const workspace = new Workspace(screenManager, 0.3, true);
|
||||
|
||||
// Update model ...
|
||||
const mindmap = new Mindmap();
|
||||
const model = new NodeModel('CentralTopic', mindmap);
|
||||
model.setText(text);
|
||||
model.setBackgroundColor(backgroundColor);
|
||||
model.setBorderColor(borderColor);
|
||||
model.setShapeType(shapeType);
|
||||
model.setFontColor(fontColor);
|
||||
model.setFontFamily(fontFamily);
|
||||
model.setFontSize(fontSize);
|
||||
|
||||
if (noteText) {
|
||||
const note = new NoteModel({ text: noteText });
|
||||
model.addFeature(note);
|
||||
}
|
||||
|
||||
if (linkText) {
|
||||
const note = new LinkModel({ url: linkText });
|
||||
model.addFeature(note);
|
||||
}
|
||||
|
||||
if (eicon) {
|
||||
(eicon as string[]).forEach((icon) => {
|
||||
const emodel = new EmojiIconModel({ id: icon });
|
||||
model.addFeature(emodel);
|
||||
});
|
||||
}
|
||||
|
||||
// Create topic UI element ...
|
||||
mindmap.addBranch(model);
|
||||
const centralTopic = new CentralTopic(model, { readOnly: true });
|
||||
workspace.append(centralTopic);
|
||||
|
||||
// Register refresh hook ..
|
||||
registerRefreshHook(centralTopic);
|
||||
|
||||
return divElem;
|
||||
};
|
||||
|
||||
export default createTopic;
|
@ -23,7 +23,7 @@
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"src/**/*", "storybook/src/stories",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
|
Loading…
Reference in New Issue
Block a user