Merge branch 'feature/landingpage' of https://github.com/ueberdosis/tiptap-next into feature/landingpage

This commit is contained in:
Philipp Kühn 2021-02-03 18:36:58 +01:00
commit 31ed0fb89b
41 changed files with 574 additions and 31 deletions

2
docs/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
static/images/*
!static/images/.gitkeep

BIN
docs/fonts/Inter-Black.otf Normal file

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/Inter-Bold.otf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/Inter-Italic.otf Normal file

Binary file not shown.

BIN
docs/fonts/Inter-Light.otf Normal file

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/Inter-Medium.otf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/Inter-Thin.otf Normal file

Binary file not shown.

Binary file not shown.

BIN
docs/fonts/Inter-V.ttf Normal file

Binary file not shown.

View File

@ -1,5 +1,45 @@
const fs = require('fs')
const { createCanvas, registerFont } = require('canvas')
const path = require('path')
const globby = require('globby')
registerFont('fonts/Inter-Regular.otf', { family: 'InterRegular' })
registerFont('fonts/Inter-Medium.otf', { family: 'InterMedium' })
const wrapText = function (context, text, x, y, maxWidth, lineHeight) {
const words = text.split(' ')
let line = ''
for (let n = 0; n < words.length; n += 1) {
const testLine = `${line + words[n]} `
const metrics = context.measureText(testLine)
const testWidth = metrics.width
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y)
line = `${words[n]} `
y += lineHeight
} else {
line = testLine
}
}
context.fillText(line, x, y)
}
const calculateReadingTime = function (text) {
const wordsPerMinute = 200
const textLength = text.split(' ').length
if (textLength > 0) {
const value = Math.ceil(textLength / wordsPerMinute)
if (value === 1) {
return `${value} minute`
}
return `${value} minutes`
}
}
// const TypeDoc = require('typedoc')
// const packages = globby.sync('../packages/*', { onlyDirectories: true })
@ -142,4 +182,67 @@ module.exports = function (api) {
.set(`@tiptap/${name}`, path.resolve(`../packages/${name}/src/index.ts`))
})
})
// Generate OpenGraph images for all pages
api.onCreateNode(options => {
// if (process.env.NODE_ENV !== 'production') {
// return null
// }
if (options.internal.typeName !== 'DocPage') {
return
}
const imagePath = `static/images${options.path}`
const imageFile = `static/images${options.path}og-image.png`
// console.log(`Found Post “${options.title}” in ${options.internal.origin} …`)
const width = 1200
const height = 630
const border = 40
const canvas = createCanvas(width, height)
const context = canvas.getContext('2d')
// background
context.fillStyle = '#000000'
context.fillRect(0, 0, width, height)
// project
const project = 'tiptap documentation'
context.textBaseline = 'top'
context.fillStyle = '#666666'
context.font = '32pt InterRegular'
context.fillText(project, border, border)
// title
const { title } = options
const lineHeight = 96
context.textBaseline = 'top'
context.fillStyle = '#ffffff'
context.font = '58pt InterMedium'
wrapText(context, title, border, border + 60 + border, width - border - border, lineHeight)
// reading time
const readingTime = calculateReadingTime(options.content)
context.textBaseline = 'bottom'
context.fillStyle = '#666666'
context.font = '32pt InterRegular'
context.fillText(readingTime, border, height - border)
// store
const buffer = canvas.toBuffer('image/png')
fs.mkdir(imagePath, { recursive: true }, error => {
if (error) {
throw error
}
fs.writeFileSync(imageFile, buffer)
// console.log(`OpenGraph image generated (${imageFile}).`)
})
})
}

View File

@ -12,6 +12,7 @@
"@gridsome/transformer-json": "^0.2.1",
"@gridsome/vue-remark": "^0.2.6",
"@mvasilkov/outdent": "^1.0.4",
"canvas": "^2.6.1",
"collect.js": "^4.28.6",
"d3": "^6.5.0",
"globby": "^11.0.0",

View File

@ -23,6 +23,8 @@
</div>
</template>
<script>
/*
<static-query>
query {
packages: allPackage {
@ -34,8 +36,7 @@ query {
}
}
</static-query>
<script>
*/
// import collect from 'collect.js'
import { VueLive } from 'vue-live'
import CustomLayout from './CustomLayout'

View File

@ -0,0 +1,7 @@
context('/demos/Examples/Images', () => {
before(() => {
cy.visit('/demos/Examples/Images')
})
// TODO: Write tests
})

View File

@ -0,0 +1,79 @@
<template>
<div v-if="editor">
<button @click="addImage">
add image from URL
</button>
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor } from '@tiptap/core'
import { EditorContent } from '@tiptap/vue'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Image from '@tiptap/extension-image'
import Dropcursor from '@tiptap/extension-dropcursor'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
methods: {
addImage() {
const url = window.prompt('URL')
if (url) {
this.editor.chain().focus().setImage({ src: url }).run()
}
},
},
mounted() {
this.editor = new Editor({
extensions: [
Document,
Paragraph,
Text,
Image,
Dropcursor,
],
content: `
<p>This is a basic example of implementing images. Drag to re-order.</p>
<img src="https://source.unsplash.com/8xznAGy4HcY/800x400" />
<img src="https://source.unsplash.com/K9QHL52rE2k/800x400" />
`,
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
/* Basic editor styles */
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
img {
max-width: 100%;
height: auto;
&.ProseMirror-selectednode {
outline: 3px solid #68CEF8;
}
}
}
</style>

View File

@ -0,0 +1,70 @@
import { Node, Command } from '@tiptap/core'
export interface IframeOptions {
allowFullscreen: boolean,
HTMLAttributes: {
[key: string]: any
},
}
export default Node.create({
name: 'iframe',
group: 'block',
// selectable: false,
defaultOptions: <IframeOptions>{
allowFullscreen: true,
HTMLAttributes: {
class: 'iframe-wrapper',
},
},
addAttributes() {
return {
src: {
default: null,
},
frameborder: {
default: 0,
},
allowfullscreen: {
default: this.options.allowFullscreen,
parseHTML: () => {
return {
allowfullscreen: this.options.allowFullscreen,
}
},
},
}
},
parseHTML() {
return [{
tag: 'iframe',
}]
},
renderHTML({ HTMLAttributes }) {
return ['div', this.options.HTMLAttributes, ['iframe', HTMLAttributes, 0]]
},
addCommands() {
return {
/**
* Add an iframe
*/
setIframe: (options: { src: string }): Command => ({ tr, dispatch }) => {
const { selection } = tr
const node = this.type.create(options)
if (dispatch) {
tr.replaceRangeWith(selection.from, selection.to, node)
}
return true
},
}
},
})

View File

@ -0,0 +1,84 @@
<template>
<div v-if="editor">
<button @click="addImage">
add iframe
</button>
<editor-content :editor="editor" />
</div>
</template>
<script>
import {
Editor, EditorContent, defaultExtensions,
} from '@tiptap/vue-starter-kit'
import Iframe from './iframe'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
...defaultExtensions(),
Iframe,
],
content: `
<p>Here is an exciting video:</p>
<iframe src="https://www.youtube.com/embed/XIMLoLxmTDw" frameborder="0" allowfullscreen></iframe>
`,
})
},
methods: {
addImage() {
const url = window.prompt('URL')
if (url) {
this.editor.chain().focus().setIframe({ src: url }).run()
}
},
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
.iframe-wrapper {
position: relative;
padding-bottom: 100/16*9%;
height: 0;
overflow: hidden;
width: 100%;
height: auto;
&.ProseMirror-selectednode {
outline: 3px solid #68CEF8;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,67 @@
import { Extension } from '@tiptap/core'
import { Decoration, DecorationSet } from 'prosemirror-view'
import { Plugin } from 'prosemirror-state'
export interface PlaceholderOptions {
emptyEditorClass: string,
emptyNodeClass: string,
placeholder: string | Function,
showOnlyWhenEditable: boolean,
showOnlyCurrent: boolean,
}
export default Extension.create({
name: 'placeholder',
defaultOptions: <PlaceholderOptions>{
emptyEditorClass: 'is-editor-empty',
emptyNodeClass: 'is-empty',
placeholder: 'Write something …',
showOnlyWhenEditable: true,
showOnlyCurrent: true,
},
addProseMirrorPlugins() {
return [
new Plugin({
props: {
decorations: ({ doc, selection }) => {
const active = this.editor.isEditable || !this.options.showOnlyWhenEditable
const { anchor } = selection
const decorations: Decoration[] = []
const isEditorEmpty = doc.textContent.length === 0
if (!active) {
return
}
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize)
const isNodeEmpty = node.content.size === 0
if ((hasAnchor || !this.options.showOnlyCurrent) && isNodeEmpty) {
const classes = [this.options.emptyNodeClass]
if (isEditorEmpty) {
classes.push(this.options.emptyEditorClass)
}
const decoration = Decoration.node(pos, pos + node.nodeSize, {
class: classes.join(' '),
'data-empty-text': typeof this.options.placeholder === 'function'
? this.options.placeholder(node)
: this.options.placeholder,
})
decorations.push(decoration)
}
return false
})
return DecorationSet.create(doc, decorations)
},
},
}),
]
},
})

View File

@ -0,0 +1,56 @@
<template>
<editor-content :editor="editor" />
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-starter-kit'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Placeholder from './extension/placeholder'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document,
Paragraph,
Text,
Placeholder,
],
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
/* Basic editor styles */
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
}
/* Placeholder */
.ProseMirror p.is-editor-empty:first-child::before {
content: attr(data-empty-text);
float: left;
color: #ced4da;
pointer-events: none;
height: 0;
}
</style>

View File

@ -31,7 +31,9 @@ export default {
addImage() {
const url = window.prompt('URL')
this.editor.chain().focus().setImage({ src: url }).run()
if (url) {
this.editor.chain().focus().setImage({ src: url }).run()
}
},
},
@ -68,6 +70,10 @@ export default {
img {
max-width: 100%;
height: auto;
&.ProseMirror-selectednode {
outline: 3px solid #68CEF8;
}
}
}
</style>

View File

@ -0,0 +1,3 @@
# Images
<demo name="Examples/Images" />

View File

@ -7,6 +7,7 @@ Congratulations! Youve found our secret playground with a list of experiments
* [Comments](/experiments/comments)
* [Color](/experiments/color)
* [Commands](/experiments/commands)
* [Embeds](/experiments/embeds)
## Waiting for approval
* [Placeholder](/experiments/placeholder)

View File

@ -0,0 +1,5 @@
# Embeds
⚠️ Experiment
<demo name="Experiments/Embeds" highlight="" />

View File

@ -0,0 +1,5 @@
# Placeholder
⚠️ Experiment
<demo name="Experiments/Placeholder" highlight="" />

View File

@ -1,7 +1,7 @@
# Collaborative editing
:::pro Become a sponsor
Using collaborative editing in production? Do the right thing and [sponsor our work](/sponsor)!
:::pro Professionals
Using the collaborative editing commercially? [Become a sponsor](/sponsor) to fund its development!
:::
## toc
@ -9,7 +9,7 @@ Using collaborative editing in production? Do the right thing and [sponsor our w
## Introduction
Real-time collaboration, syncing between different devices and working offline used to be hard. We provide everything you need to keep everything in sync, conflict-free with the power of [Y.js](https://github.com/yjs/yjs). The following guide explains all things to take into account when you consider to make tiptap collaborative. Dont worry, a production-grade setup doesnt require much code.
## Configure collaboration
## Configure the editor
The underyling schema tiptap uses is an excellent foundation to sync documents. With the [`Collaboration`](/api/extensions/collaboration) you can tell tiptap to track changes to the document with [Y.js](https://github.com/yjs/yjs).
Y.js is a conflict-free replicated data types implementation, or in other words: Its reaaally good in merging changes. And to achieve that, changes dont have to come in order. Its totally fine to change a document while being offline and merge the it with other changes when the device is online again.
@ -209,17 +209,13 @@ All changes will be stored in the browser then, even if you close the tab, go of
Yes, its magic. As already mentioned, that is all based on the fantastic Y.js framework. And if youre using it, or our integration, you should definitely [sponsor Kevin Jahns on GitHub](https://github.com/dmonad), he is the brain behind Y.js.
## Store the content
## A plug & play backend
Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Lets go through a few common use cases here!
### Where is it?
:::warning Work in progress
Our plug & play collaboration backend hocuspocus is still work in progress. Were setting up a dedicated website and documentation, and need to add one or two features before publishing it.
If you want to give it a try, send us an email to humans@tiptap.dev to receive early access.
Our plug & play collaboration backend hocuspocus is still work in progress. If you want to give it a try, send us an email to [humans@tiptap.dev](mailto:humans@tiptap.dev) to receive early access.
:::
<!-- :::pro Backend as a Service (Paid)
Dont want to wrap your head around the backend part? No worries, we offer a managed backend. For less than 1.000 documents, its $49/month (VAT may apply) and probably saves you a ton of time. Send us an email to [humans@tiptap.dev](mailto:humans@tiptap.dev) for further details.
::: -->
### The document name
The document name is `'example-document'` in all examples here, but it could be any string. In a real-world app youd probably add the name of your entity and the ID of the entity. Here is how that could look like:

View File

@ -7,6 +7,10 @@
<body ${bodyAttrs}>
${app}
${scripts}
${process.env.NODE_ENV === 'production'
? '<script async defer data-ignore-pages="/demos/*" src="https://data.next.tiptap.dev/latest.js"></script><noscript><img src="https://data.next.tiptap.dev/image.gif" alt=""></noscript>'
: ''
}
${process.env.NODE_ENV === 'production'
? '<script async defer data-exclude="/demos/**" data-domain="next.tiptap.dev" src="https://plausible.io/js/plausible.exclusions.js"></script>'
: ''

View File

@ -41,6 +41,9 @@
- title: Tables
link: /examples/tables
type: draft
- title: Images
link: /examples/images
type: draft
- title: Guide
items:

View File

@ -1,17 +1,24 @@
<template>
<div class="error-page">
Oh no, page not found.
<g-link
to="/"
>
Back
</g-link>
<div class="error-page__content">
Oh no, we cant find this page.
<g-link
to="/"
>
Go back
</g-link>
</div>
</div>
</template>
<style lang="scss">
.error-page {
margin: 5rem 1rem;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
// margin: 5rem 1rem;
text-align: center;
color: rgba($colorWhite, 0.4);

View File

@ -37,7 +37,7 @@ export default {
},
{
property: 'og:image',
content: 'https://next.tiptap.dev/og-image.png',
content: this.getOpenGraphImage(),
},
/* Twitter */
{
@ -50,7 +50,7 @@ export default {
},
{
name: 'twitter:image',
content: 'https://next.tiptap.dev/og-image.png',
content: this.getOpenGraphImage(),
},
{
name: 'twitter:site',
@ -59,5 +59,14 @@ export default {
],
}
},
methods: {
getOpenGraphImage() {
const path = this.$route.path.replace(/\/$/, '')
return path === ''
? 'https://next.tiptap.dev/og-image.png'
: `/images${path}/og-image.png`
},
},
}
</script>

0
docs/static/images/.gitkeep vendored Normal file
View File

View File

@ -3909,6 +3909,15 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001181:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001183.tgz#7a57ba9d6584119bb5f2bc76d3cc47ba9356b3e2"
integrity sha512-7JkwTEE1hlRKETbCFd8HDZeLiQIUcl8rC6JgNjvHCNaxOeNmQ9V4LvQXRUsKIV2CC73qKxljwVhToaA3kLRqTw==
canvas@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.6.1.tgz#0d087dd4d60f5a5a9efa202757270abea8bef89e"
integrity sha512-S98rKsPcuhfTcYbtF53UIJhcbgIAK533d1kJKMwsMwAIFgfd58MOyxRud3kktlzWiEkFliaJtvyZCBtud/XVEA==
dependencies:
nan "^2.14.0"
node-pre-gyp "^0.11.0"
simple-get "^3.0.3"
case-sensitive-paths-webpack-plugin@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7"
@ -5486,7 +5495,7 @@ detect-indent@^6.0.0:
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd"
integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==
detect-libc@^1.0.3:
detect-libc@^1.0.2, detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
@ -7827,7 +7836,7 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24:
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -9934,7 +9943,7 @@ mz@^2.5.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.12.1, nan@^2.13.2:
nan@^2.12.1, nan@^2.13.2, nan@^2.14.0:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
@ -9976,6 +9985,15 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
needle@^2.2.1:
version "2.6.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe"
integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==
dependencies:
debug "^3.2.6"
iconv-lite "^0.4.4"
sax "^1.2.4"
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
@ -10104,6 +10122,22 @@ node-libs-browser@^2.2.1:
util "^0.11.0"
vm-browserify "^1.0.1"
node-pre-gyp@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
node-releases@^1.1.70:
version "1.1.70"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.70.tgz#66e0ed0273aa65666d7fe78febe7634875426a08"
@ -10251,7 +10285,7 @@ npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1:
semver "^5.6.0"
validate-npm-package-name "^3.0.0"
npm-packlist@^1.4.4:
npm-packlist@^1.1.6, npm-packlist@^1.4.4:
version "1.4.8"
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e"
integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==
@ -10283,7 +10317,7 @@ npm-run-path@^4.0.0:
dependencies:
path-key "^3.0.0"
npmlog@^4.0.0, npmlog@^4.0.1, npmlog@^4.1.2:
npmlog@^4.0.0, npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
@ -12546,7 +12580,7 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
@ -12735,7 +12769,7 @@ sass@^1.18.0:
dependencies:
chokidar ">=2.0.0 <4.0.0"
sax@~1.2.4:
sax@^1.2.4, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@ -13795,7 +13829,7 @@ tar-stream@^2.1.4:
inherits "^2.0.3"
readable-stream "^3.1.1"
tar@^4.4.10, tar@^4.4.12, tar@^4.4.8:
tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8:
version "4.4.13"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==