diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 7a5e369..72af7ae 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -28,5 +28,14 @@ jobs:
- name: Build Demo
run: npm run build:demo
- - name: Test e2e
- run: npm run test:e2e
+ - name: Run E2E Test
+ uses: cypress-io/github-action@v5
+ with:
+ start: npm run preview
+ record: true
+ browser: chrome
+ env:
+ # Recommended: pass the GitHub token lets this action correctly
+ # determine the unique run id necessary to re-run the checks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d65c732..92ff789 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,7 +33,16 @@ jobs:
run: npm run build:demo
- name: Run E2E Test
- run: npm run test:e2e
+ uses: cypress-io/github-action@v5
+ with:
+ start: npm run preview
+ record: true
+ browser: chrome
+ env:
+ # Recommended: pass the GitHub token lets this action correctly
+ # determine the unique run id necessary to re-run the checks
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
- name: Deploy to vue-live.surge.sh
if: ${{ github.ref == 'refs/heads/master' }}
diff --git a/README.md b/README.md
index 4b14ee6..e024242 100644
--- a/README.md
+++ b/README.md
@@ -178,6 +178,15 @@ export default {
```
+### `directives`
+
+**Type** Object:
+
+- key: registration name
+- value: VueJs directive object
+
+You can use this prop in the same fashion as `components` above.
+
### `requires`
**Type** Object:
diff --git a/cypress.config.ts b/cypress.config.ts
index ef48d11..cc43ce3 100644
--- a/cypress.config.ts
+++ b/cypress.config.ts
@@ -1,6 +1,7 @@
import { defineConfig } from "cypress";
export default defineConfig({
+ projectId: 'wbesaj',
e2e: {
specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
baseUrl: "http://localhost:4173",
diff --git a/cypress/e2e/LiveRefresh.cy.ts b/cypress/e2e/LiveRefresh.cy.ts
index 193c460..27bfd7f 100644
--- a/cypress/e2e/LiveRefresh.cy.ts
+++ b/cypress/e2e/LiveRefresh.cy.ts
@@ -10,15 +10,26 @@ describe("Live Refresh", () => {
});
it("changes the render after code change", () => {
+ const textToReplace = "inline component";
+ const textReplaced = "red component";
+
cy.get("@preview")
- .find(".v3dp__datepicker input")
- .should("not.have.value", "");
+ .get("[data-cy=my-button]")
+ .should("have.text", textToReplace);
- const codeToDelete = ' v-model="today"/>';
cy.get("@container")
- .find(".prism-editor-wrapper textarea")
- .type(`${"{backspace}".repeat(codeToDelete.length)}/>`);
+ .find(".prism-editor-wrapper textarea").as("editor");
+
+ cy.get("@editor").invoke("val")
+ .then((val) => {
+ cy.get("@editor")
+ .clear()
+ .invoke('val', `${val}`.replace(textToReplace, textReplaced))
+ .trigger('input');
- cy.get("@preview").find(".v3dp__datepicker input").should("have.value", "");
+ cy.get("@preview")
+ .get("[data-cy=my-button]")
+ .should("have.text", textReplaced);
+ });
});
});
diff --git a/demo/App.vue b/demo/App.vue
index c3651e3..d24a104 100644
--- a/demo/App.vue
+++ b/demo/App.vue
@@ -14,7 +14,7 @@
You can edit this ->
-
log('Error on first example', e)" />
@@ -27,8 +27,8 @@
file components as well
- SFC with setup
-
+ VSG partial mode or pure template
+
Pure JavaScript code
Or if you prefer to, use the new Vue() format
@@ -65,6 +65,9 @@
JSX
+ TSX
+
+
Double Root
@@ -92,6 +95,7 @@ import codeSfc from "./assets/Button.vue?raw";
import codeSfcSetup from "./assets/ButtonSetup.vue?raw";
import codeJs from "./assets/input.js?raw";
import realjsx from "./assets/real.jsx?raw";
+import blobtsx from "./assets/blob.tsx?raw";
import codeTemplate from "./assets/PureTemplate.html?raw";
import doubleRoot from "./assets/PureTemplateDoubleRoot.html?raw";
import codeChicago from "./assets/Chicago.jsx?raw";
@@ -116,6 +120,7 @@ export default defineComponent({
CustomLayout: markRaw(CustomLayout),
chicagoRequires: { "./chicagoNeighbourhoods": all },
realjsx,
+ blobtsx,
separateCode: codeSfc,
doubleRoot,
openExamples: false,
diff --git a/demo/assets/ButtonSetup.vue b/demo/assets/ButtonSetup.vue
index ad928d8..035fc4a 100644
--- a/demo/assets/ButtonSetup.vue
+++ b/demo/assets/ButtonSetup.vue
@@ -1,5 +1,15 @@
@@ -7,13 +17,12 @@ const msg = ref("Push Me")
Colored Text
-
+
+
+ {{ msg }}
+
+
+
+
-
-
-
+
\ No newline at end of file
diff --git a/demo/assets/blob.tsx b/demo/assets/blob.tsx
new file mode 100644
index 0000000..51553ec
--- /dev/null
+++ b/demo/assets/blob.tsx
@@ -0,0 +1,12 @@
+const args = {
+ type: "button",
+ value: "update me",
+} as const;
+
+type Key = keyof typeof args;
+
+export default {
+ render() {
+ return ;
+ },
+};
diff --git a/package-lock.json b/package-lock.json
index 1e881a8..8242306 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,7 +17,8 @@
"debounce": "^1.2.1",
"hash-sum": "^2.0.0",
"prismjs": "^1.29.0",
- "vue-inbrowser-compiler-sucrase": "^4.60.0",
+ "vue-inbrowser-compiler-sucrase": "^4.62.0",
+ "vue-inbrowser-compiler-utils": "^4.62.1",
"vue-prism-editor": "^2.0.0-alpha.2"
},
"devDependencies": {
@@ -4214,23 +4215,23 @@
}
},
"node_modules/vue-inbrowser-compiler-independent-utils": {
- "version": "4.56.2",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-independent-utils/-/vue-inbrowser-compiler-independent-utils-4.56.2.tgz",
- "integrity": "sha512-szE2vZDSkZlItq+K4MevgvCGKt5IzM6OkIjyCuj/09ty2akixeQGNFRXyDELMdmVVzmN+9nJn02YKnoPkhXHwA==",
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-independent-utils/-/vue-inbrowser-compiler-independent-utils-4.62.0.tgz",
+ "integrity": "sha512-Xj7phxND9kycttv1KxvzenyqdjVQLf8V5LDREO+x+2FwM99pKhUg2VoxPHlRKghcvOvBv9Fs1iaU9kJCl0DjbQ==",
"peerDependencies": {
"vue": ">=2"
}
},
"node_modules/vue-inbrowser-compiler-sucrase": {
- "version": "4.60.0",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-sucrase/-/vue-inbrowser-compiler-sucrase-4.60.0.tgz",
- "integrity": "sha512-JTfksUvz4b8UFRJ28iHFh2sH6/6+14Bj5FEiqCmHuFzULiQKN8ZAWTg4WqmDRRLfbmKqNzUpzoIEv8+pyGFMQQ==",
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-sucrase/-/vue-inbrowser-compiler-sucrase-4.62.0.tgz",
+ "integrity": "sha512-i/04sJf6PhLQX7Q9orrz7j+8jz/6zNugkPZkTzDVyXT67QclXF7Rg6FcAh90pjfKGTUwsxLaXC9vOIh+ePvWbg==",
"dependencies": {
"@babel/parser": "^7.13.12",
"camelcase": "^5.3.1",
"detect-browser": "^5.2.0",
"sucrase": "3.29.0",
- "vue-inbrowser-compiler-utils": "^4.55.0",
+ "vue-inbrowser-compiler-utils": "^4.62.0",
"walkes": "^0.2.1"
},
"peerDependencies": {
@@ -4238,13 +4239,13 @@
}
},
"node_modules/vue-inbrowser-compiler-utils": {
- "version": "4.56.5",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-utils/-/vue-inbrowser-compiler-utils-4.56.5.tgz",
- "integrity": "sha512-EYAf8L4ibXJhlPDZDAwDS0eHCek8kU2PoJGrJh0RpIm8AHxuIrLe4mPClWmQ0g9PBNQNdW9JvhWvRpzPD27mmw==",
+ "version": "4.62.1",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-utils/-/vue-inbrowser-compiler-utils-4.62.1.tgz",
+ "integrity": "sha512-OBXww64WgfxgAwPalZHWAbrVqcAcmeZbsv74uaOL9eABUAKS6sXEbb+RjSXOjPsgfDONMg9zwCPiMOnPVRXlzQ==",
"dependencies": {
"camelcase": "^5.3.1",
"vue-inbrowser-compiler-demi": "^4.56.5",
- "vue-inbrowser-compiler-independent-utils": "^4.55.0"
+ "vue-inbrowser-compiler-independent-utils": "^4.62.0"
},
"peerDependencies": {
"vue": ">=2"
@@ -7395,32 +7396,32 @@
"requires": {}
},
"vue-inbrowser-compiler-independent-utils": {
- "version": "4.56.2",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-independent-utils/-/vue-inbrowser-compiler-independent-utils-4.56.2.tgz",
- "integrity": "sha512-szE2vZDSkZlItq+K4MevgvCGKt5IzM6OkIjyCuj/09ty2akixeQGNFRXyDELMdmVVzmN+9nJn02YKnoPkhXHwA==",
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-independent-utils/-/vue-inbrowser-compiler-independent-utils-4.62.0.tgz",
+ "integrity": "sha512-Xj7phxND9kycttv1KxvzenyqdjVQLf8V5LDREO+x+2FwM99pKhUg2VoxPHlRKghcvOvBv9Fs1iaU9kJCl0DjbQ==",
"requires": {}
},
"vue-inbrowser-compiler-sucrase": {
- "version": "4.60.0",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-sucrase/-/vue-inbrowser-compiler-sucrase-4.60.0.tgz",
- "integrity": "sha512-JTfksUvz4b8UFRJ28iHFh2sH6/6+14Bj5FEiqCmHuFzULiQKN8ZAWTg4WqmDRRLfbmKqNzUpzoIEv8+pyGFMQQ==",
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-sucrase/-/vue-inbrowser-compiler-sucrase-4.62.0.tgz",
+ "integrity": "sha512-i/04sJf6PhLQX7Q9orrz7j+8jz/6zNugkPZkTzDVyXT67QclXF7Rg6FcAh90pjfKGTUwsxLaXC9vOIh+ePvWbg==",
"requires": {
"@babel/parser": "^7.13.12",
"camelcase": "^5.3.1",
"detect-browser": "^5.2.0",
"sucrase": "3.29.0",
- "vue-inbrowser-compiler-utils": "^4.55.0",
+ "vue-inbrowser-compiler-utils": "^4.62.0",
"walkes": "^0.2.1"
}
},
"vue-inbrowser-compiler-utils": {
- "version": "4.56.5",
- "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-utils/-/vue-inbrowser-compiler-utils-4.56.5.tgz",
- "integrity": "sha512-EYAf8L4ibXJhlPDZDAwDS0eHCek8kU2PoJGrJh0RpIm8AHxuIrLe4mPClWmQ0g9PBNQNdW9JvhWvRpzPD27mmw==",
+ "version": "4.62.1",
+ "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler-utils/-/vue-inbrowser-compiler-utils-4.62.1.tgz",
+ "integrity": "sha512-OBXww64WgfxgAwPalZHWAbrVqcAcmeZbsv74uaOL9eABUAKS6sXEbb+RjSXOjPsgfDONMg9zwCPiMOnPVRXlzQ==",
"requires": {
"camelcase": "^5.3.1",
"vue-inbrowser-compiler-demi": "^4.56.5",
- "vue-inbrowser-compiler-independent-utils": "^4.55.0"
+ "vue-inbrowser-compiler-independent-utils": "^4.62.0"
}
},
"vue-prism-editor": {
diff --git a/package.json b/package.json
index 9949562..6ea71fc 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,8 @@
"debounce": "^1.2.1",
"hash-sum": "^2.0.0",
"prismjs": "^1.29.0",
- "vue-inbrowser-compiler-sucrase": "^4.60.0",
+ "vue-inbrowser-compiler-sucrase": "^4.62.0",
+ "vue-inbrowser-compiler-utils": "^4.62.1",
"vue-prism-editor": "^2.0.0-alpha.2"
},
"devDependencies": {
diff --git a/src/Editor.vue b/src/Editor.vue
index 7dd7ca6..7e2fd5e 100644
--- a/src/Editor.vue
+++ b/src/Editor.vue
@@ -9,7 +9,7 @@ import debounce from "debounce";
import "vue-prism-editor/dist/prismeditor.min.css";
-import makeHighlight from "./utils/highlight";
+import makeHighlight, { CONFIGURED_LANGS, type CONFIGURED_LANGS_TYPE } from "./utils/highlight";
const UPDATE_DELAY = 300;
@@ -35,9 +35,9 @@ export default defineComponent({
default: () => ({}),
},
prismLang: {
- type: String,
+ type: String as PropType,
default: "html",
- validator: (val: string) => ["html", "vsg"].includes(val),
+ validator: (val: string) => CONFIGURED_LANGS.includes(val as CONFIGURED_LANGS_TYPE),
},
jsx: {
type: Boolean,
@@ -58,7 +58,7 @@ export default defineComponent({
*/
stableCode: this.code,
highlight: (() => (code: string) => code) as (
- lang: "vue" | "vsg",
+ lang: CONFIGURED_LANGS_TYPE,
jsxInExamples: boolean
) => (code: string, errorLoc: any) => string,
};
@@ -73,7 +73,7 @@ export default defineComponent({
},
methods: {
highlighter(code: string) {
- return this.highlight(this.prismLang as "vue" | "vsg", this.jsx)(
+ return this.highlight(this.prismLang, this.jsx)(
code,
this.squiggles && this.error && this.error.loc
);
diff --git a/src/Preview.vue b/src/Preview.vue
index 8e134e8..c558675 100644
--- a/src/Preview.vue
+++ b/src/Preview.vue
@@ -143,11 +143,7 @@ export default defineComponent({
}
},
async renderComponent(code: string) {
- let options = defineComponent({
- render() {
- return h("div");
- },
- });
+ let options = defineComponent({});
let style;
try {
const renderedComponent = compileScript(
@@ -183,18 +179,6 @@ export default defineComponent({
concatenate,
h
) || {}));
- if (options.render) {
- const preview = this;
- const originalRender = options.render;
- options.render = function (...args: any[]) {
- try {
- return originalRender.call(this, ...args);
- } catch (e) {
- preview.handleError(e);
- return;
- }
- };
- }
options.name = "VueLiveCompiledExample";
};
await calcOptions();
@@ -218,7 +202,7 @@ export default defineComponent({
options.data = () => mergeData;
}
}
-
+
const template = renderedComponent.raw.template
if (template) {
checkTemplate({
@@ -266,6 +250,8 @@ export default defineComponent({
return;
}
+ console.log({render:options.render})
+
this.previewedComponent = markRaw(options);
this.iteration = this.iteration + 1;
this.error = false;
diff --git a/src/VueLive.vue b/src/VueLive.vue
index c77b8ed..ad0c9cc 100644
--- a/src/VueLive.vue
+++ b/src/VueLive.vue
@@ -25,11 +25,12 @@ import hash from "hash-sum";
import Preview from "./Preview.vue";
import Editor from "./Editor.vue";
import VueLiveDefaultLayout from "./VueLiveDefaultLayout.vue";
+import type { CONFIGURED_LANGS_TYPE } from "./utils/highlight";
const LANG_TO_PRISM = {
vue: "html",
vsg: "vsg",
-};
+} as const;
const UPDATE_DELAY = 300;
@@ -140,7 +141,7 @@ export default defineComponent({
return {
model: this.code,
lang: "vue",
- prismLang: "html",
+ prismLang: "html" as CONFIGURED_LANGS_TYPE,
VueLiveDefaultLayout: markRaw(VueLiveDefaultLayout),
/**
* this data only gets changed when changing language.
diff --git a/src/utils/highlight.ts b/src/utils/highlight.ts
index c5db97d..69824e0 100644
--- a/src/utils/highlight.ts
+++ b/src/utils/highlight.ts
@@ -1,4 +1,4 @@
-// NOTE: this weird way of importing prism is necessary because
+// NOTE: this weird way of importing prism is necessary because
// prism is not a ESM ready library
import pkg from "prismjs";
const { highlight: prismHighlight, languages } = pkg;
@@ -8,14 +8,19 @@ import "prismjs/components/prism-markup.js";
import "prismjs/components/prism-javascript.js";
import "prismjs/components/prism-typescript.js";
import "prismjs/components/prism-jsx.js";
+import "prismjs/components/prism-tsx.js";
import "prismjs/components/prism-css.js";
import getScript from "./getScript";
import { parseComponent } from "vue-inbrowser-compiler-sucrase";
+export const CONFIGURED_LANGS = ["html", "vsg", "jsx", "tsx"] as const;
+export type CONFIGURED_LANGS_TYPE = (typeof CONFIGURED_LANGS)[number];
+
export default async function () {
- return function (lang: "vsg" | "vue", jsxInExamples: boolean) {
+ return function (lang: CONFIGURED_LANGS_TYPE, jsxInExamples: boolean) {
if (lang === "vsg") {
+ // render vsg format
return (code: string, errorLoc: any) => {
if (!code) {
return "";
@@ -23,7 +28,7 @@ export default async function () {
const scriptCode = getScript(code, jsxInExamples);
const scriptCodeHighlighted = prismHighlight(
scriptCode,
- languages[jsxInExamples ? "jsx" : "js"],
+ languages[jsxInExamples ? "tsx" : "ts"],
lang
);
if (code.length === scriptCode.length) {
@@ -45,7 +50,8 @@ export default async function () {
templateHighlighted
);
};
- } else {
+ } else if (lang === "html") {
+ // render vue SFC component format
const langScheme = languages.html;
return (code: string) => {
@@ -70,6 +76,12 @@ export default async function () {
)
: htmlHighlighted;
};
+ } else {
+ // all other formats
+ const langScheme = languages[lang];
+ return (code: string) => {
+ return prismHighlight(code, langScheme, lang);
+ };
}
};
}
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 2d83f5e..d595710 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -5,12 +5,14 @@
"src/**/*",
"src/**/*.vue",
"demo/**/*.vue",
- "demo/**/*.ts"
+ "demo/**/*.ts",
+ "demo/**/*.tsx"
],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"rootDir": ".",
- "noEmit": true
+ "noEmit": true,
+ "jsx":"preserve"
}
}