Browse Source

Improves code editor types, adds es5 lib

main
Steve Ruiz 4 years ago
parent
commit
61399fb9d0

+ 15
- 16
components/code-panel/code-editor.tsx View File

@@ -1,5 +1,6 @@
1 1
 import Editor, { Monaco } from '@monaco-editor/react'
2 2
 import useTheme from 'hooks/useTheme'
3
+import libImport from './es5-lib'
3 4
 import typesImport from './types-import'
4 5
 import React, { useCallback, useEffect, useRef } from 'react'
5 6
 import styled from 'styles'
@@ -46,17 +47,10 @@ export default function CodeEditor({
46 47
     if (monacoRef) {
47 48
       monacoRef.current = monaco
48 49
     }
50
+
49 51
     rMonaco.current = monaco
50 52
 
51
-    monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
52
-      allowJs: true,
53
-      checkJs: false,
54
-      strict: false,
55
-      noLib: true,
56
-      lib: ['es6'],
57
-      target: monaco.languages.typescript.ScriptTarget.ES2016,
58
-      allowNonTsExtensions: true,
59
-    })
53
+    // Set the compiler options.
60 54
 
61 55
     monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
62 56
       allowJs: true,
@@ -68,27 +62,31 @@ export default function CodeEditor({
68 62
       allowNonTsExtensions: true,
69 63
     })
70 64
 
65
+    // Sync the intellisense on load.
66
+
71 67
     monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true)
72
-    monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)
73 68
 
74
-    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
75
-      noSemanticValidation: false,
76
-      noSyntaxValidation: false,
77
-    })
69
+    // Run both semantic and syntax validation.
78 70
 
79 71
     monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
80 72
       noSemanticValidation: false,
81 73
       noSyntaxValidation: false,
82 74
     })
83 75
 
76
+    // Add custom types
77
+
84 78
     monaco.languages.typescript.typescriptDefaults.addExtraLib(
85 79
       typesImport.content
86 80
     )
87 81
 
88
-    monaco.languages.typescript.javascriptDefaults.addExtraLib(
89
-      typesImport.content
82
+    // Add es5 library types
83
+
84
+    monaco.languages.typescript.typescriptDefaults.addExtraLib(
85
+      libImport.content
90 86
     )
91 87
 
88
+    // Use prettier as a formatter
89
+
92 90
     monaco.languages.registerDocumentFormattingEditProvider('typescript', {
93 91
       async provideDocumentFormattingEdits(model) {
94 92
         try {
@@ -223,6 +221,7 @@ export default function CodeEditor({
223 221
         beforeMount={handleBeforeMount}
224 222
         onMount={handleMount}
225 223
         onChange={handleChange}
224
+        defaultPath="index.ts"
226 225
       />
227 226
     </EditorContainer>
228 227
   )

+ 5459
- 0
components/code-panel/es5-lib.ts
File diff suppressed because it is too large
View File


+ 383
- 51
components/code-panel/types-import.ts View File

@@ -8,10 +8,6 @@ export default {
8 8
   name: 'types.ts',
9 9
   content: `
10 10
 
11
-type Partial<T> = { [P in keyof T]?: T[P]; };
12
-
13
-type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
14
-  
15 11
 type DeepPartial<T> = {
16 12
   [P in keyof T]?: DeepPartial<T[P]>;
17 13
 };
@@ -141,7 +137,6 @@ interface TextShape extends BaseShape {
141 137
   type: ShapeType.Text
142 138
   text: string
143 139
   scale: number
144
-  fontSize: FontSize
145 140
 }
146 141
 
147 142
 interface GroupShape extends BaseShape {
@@ -187,12 +182,6 @@ type Shape = Readonly<MutableShape>
187 182
 
188 183
 type ShapeByType<T extends ShapeType> = Shapes[T]
189 184
 
190
-interface CodeFile {
191
-  id: string
192
-  name: string
193
-  code: string
194
-}
195
-
196 185
 enum Decoration {
197 186
   Arrow = 'Arrow',
198 187
 }
@@ -209,6 +198,24 @@ interface ShapeHandle {
209 198
   point: number[]
210 199
 }
211 200
 
201
+interface CodeFile {
202
+  id: string
203
+  name: string
204
+  code: string
205
+}
206
+
207
+interface CodeError {
208
+  message: string
209
+  line: number
210
+  column: number
211
+}
212
+
213
+interface CodeResult {
214
+  shapes: Shape[]
215
+  controls: CodeControl[]
216
+  error: CodeError
217
+}
218
+
212 219
 /* -------------------------------------------------- */
213 220
 /*                      Editor UI                     */
214 221
 /* -------------------------------------------------- */
@@ -548,7 +555,11 @@ interface ShapeUtility<K extends Shape> {
548 555
   // Test whether bounds collide with or contain a shape.
549 556
   hitTestBounds(this: ShapeUtility<K>, shape: K, bounds: Bounds): boolean
550 557
 
558
+  // Get whether the shape should delete
551 559
   shouldDelete(this: ShapeUtility<K>, shape: K): boolean
560
+
561
+  // Get whether the shape should render
562
+  shouldRender(this: ShapeUtility<K>, shape: K, previous: K): boolean
552 563
 }
553 564
 
554 565
 
@@ -1825,7 +1836,7 @@ interface ShapeUtility<K extends Shape> {
1825 1836
 
1826 1837
  class CodeShape<T extends Shape> {
1827 1838
   private _shape: Mutable<T>
1828
-  private utils: ShapeUtility<T>
1839
+  protected utils: ShapeUtility<T>
1829 1840
 
1830 1841
   constructor(props: T) {
1831 1842
     this._shape = createShape(props.type, props) as Mutable<T>
@@ -1833,79 +1844,130 @@ interface ShapeUtility<K extends Shape> {
1833 1844
     codeShapes.add(this)
1834 1845
   }
1835 1846
 
1836
-  export(): Mutable<T> {
1837
-    return { ...this._shape }
1838
-  }
1839
-
1840 1847
   /**
1841 1848
    * Destroy the shape.
1849
+   *
1850
+   * \`\`\`ts
1851
+   * shape.destroy()
1852
+   * \`\`\`
1842 1853
    */
1843
-  destroy(): void {
1854
+  destroy = (): void => {
1844 1855
     codeShapes.delete(this)
1845 1856
   }
1846 1857
 
1847 1858
   /**
1848 1859
    * Move the shape to a point.
1849
-   * @param delta
1860
+   *
1861
+   * \`\`\`ts
1862
+   * shape.moveTo(100,100)
1863
+   * \`\`\`
1850 1864
    */
1851
-  moveTo(point: number[]): CodeShape<T> {
1865
+  moveTo = (point: number[]): CodeShape<T> => {
1852 1866
     return this.translateTo(point)
1853 1867
   }
1854 1868
 
1855 1869
   /**
1856 1870
    * Move the shape to a point.
1857
-   * @param delta
1871
+   *
1872
+   * \`\`\`ts
1873
+   * shape.translateTo([100,100])
1874
+   * \`\`\`
1858 1875
    */
1859
-  translateTo(point: number[]): CodeShape<T> {
1876
+  translateTo = (point: number[]): CodeShape<T> => {
1860 1877
     this.utils.translateTo(this._shape, point)
1861 1878
     return this
1862 1879
   }
1863 1880
 
1864 1881
   /**
1865 1882
    * Move the shape by a delta.
1866
-   * @param delta
1883
+   *
1884
+   * \`\`\`ts
1885
+   * shape.translateBy([100,100])
1886
+   * \`\`\`
1867 1887
    */
1868
-  translateBy(delta: number[]): CodeShape<T> {
1888
+  translateBy = (delta: number[]): CodeShape<T> => {
1869 1889
     this.utils.translateTo(this._shape, delta)
1870 1890
     return this
1871 1891
   }
1872 1892
 
1873 1893
   /**
1874 1894
    * Rotate the shape.
1895
+   *
1896
+   * \`\`\`ts
1897
+   * shape.rotateTo(Math.PI / 2)
1898
+   * \`\`\`
1875 1899
    */
1876
-  rotateTo(rotation: number): CodeShape<T> {
1900
+  rotateTo = (rotation: number): CodeShape<T> => {
1877 1901
     this.utils.rotateTo(this._shape, rotation, this.shape.rotation - rotation)
1878 1902
     return this
1879 1903
   }
1880 1904
 
1881 1905
   /**
1882 1906
    * Rotate the shape by a delta.
1907
+   *
1908
+   * \`\`\`ts
1909
+   * shape.rotateBy(Math.PI / 2)
1910
+   * \`\`\`
1883 1911
    */
1884
-  rotateBy(rotation: number): CodeShape<T> {
1912
+  rotateBy = (rotation: number): CodeShape<T> => {
1885 1913
     this.utils.rotateBy(this._shape, rotation)
1886 1914
     return this
1887 1915
   }
1888 1916
 
1889 1917
   /**
1890 1918
    * Get the shape's bounding box.
1919
+   *
1920
+   * \`\`\`ts
1921
+   * const bounds = shape.getBounds()
1922
+   * \`\`\`
1891 1923
    */
1892
-  getBounds(): CodeShape<T> {
1924
+  getBounds = (): CodeShape<T> => {
1893 1925
     this.utils.getBounds(this.shape)
1894 1926
     return this
1895 1927
   }
1896 1928
 
1897 1929
   /**
1898 1930
    * Test whether a point is inside of the shape.
1931
+   *
1932
+   * \`\`\`ts
1933
+   * const isHit = shape.hitTest()
1934
+   * \`\`\`
1899 1935
    */
1900
-  hitTest(point: number[]): CodeShape<T> {
1936
+  hitTest = (point: number[]): CodeShape<T> => {
1901 1937
     this.utils.hitTest(this.shape, point)
1902 1938
     return this
1903 1939
   }
1904 1940
 
1941
+  /**
1942
+   * Duplicate this shape.
1943
+   *
1944
+   * \`\`\`ts
1945
+   * const shapeB = shape.duplicate()
1946
+   * \`\`\`
1947
+   */
1948
+  duplicate = (): CodeShape<T> => {
1949
+    const duplicate = Object.assign(
1950
+      Object.create(Object.getPrototypeOf(this)),
1951
+      this
1952
+    )
1953
+
1954
+    duplicate._shape = createShape(this._shape.type, {
1955
+      ...this._shape,
1956
+      id: uniqueId(),
1957
+    } as any)
1958
+
1959
+    codeShapes.add(duplicate)
1960
+    return duplicate
1961
+  }
1962
+
1905 1963
   /**
1906 1964
    * Move the shape to the back of the painting order.
1965
+   *
1966
+   * \`\`\`ts
1967
+   * shape.moveToBack()
1968
+   * \`\`\`
1907 1969
    */
1908
-  moveToBack(): CodeShape<T> {
1970
+  moveToBack = (): CodeShape<T> => {
1909 1971
     const sorted = getOrderedShapes()
1910 1972
 
1911 1973
     if (sorted.length <= 1) return
@@ -1922,8 +1984,12 @@ interface ShapeUtility<K extends Shape> {
1922 1984
 
1923 1985
   /**
1924 1986
    * Move the shape to the top of the painting order.
1987
+   *
1988
+   * \`\`\`ts
1989
+   * shape.moveToFront()
1990
+   * \`\`\`
1925 1991
    */
1926
-  moveToFront(): CodeShape<T> {
1992
+  moveToFront = (): CodeShape<T> => {
1927 1993
     const sorted = getOrderedShapes()
1928 1994
 
1929 1995
     if (sorted.length <= 1) return
@@ -1941,8 +2007,12 @@ interface ShapeUtility<K extends Shape> {
1941 2007
 
1942 2008
   /**
1943 2009
    * Move the shape backward in the painting order.
2010
+   *
2011
+   * \`\`\`ts
2012
+   * shape.moveBackward()
2013
+   * \`\`\`
1944 2014
    */
1945
-  moveBackward(): CodeShape<T> {
2015
+  moveBackward = (): CodeShape<T> => {
1946 2016
     const sorted = getOrderedShapes()
1947 2017
 
1948 2018
     if (sorted.length <= 1) return
@@ -1963,8 +2033,12 @@ interface ShapeUtility<K extends Shape> {
1963 2033
 
1964 2034
   /**
1965 2035
    * Move the shape forward in the painting order.
2036
+   *
2037
+   * \`\`\`ts
2038
+   * shape.moveForward()
2039
+   * \`\`\`
1966 2040
    */
1967
-  moveForward(): CodeShape<T> {
2041
+  moveForward = (): CodeShape<T> => {
1968 2042
     const sorted = getOrderedShapes()
1969 2043
 
1970 2044
     if (sorted.length <= 1) return
@@ -1988,80 +2062,167 @@ interface ShapeUtility<K extends Shape> {
1988 2062
   }
1989 2063
 
1990 2064
   /**
1991
-   * The shape's underlying shape.
2065
+   * The shape's underlying shape (readonly).
2066
+   *
2067
+   * \`\`\`ts
2068
+   * const underlyingShape = shape.shape
2069
+   * \`\`\`
1992 2070
    */
1993
-  get shape(): T {
2071
+  get shape(): Readonly<T> {
1994 2072
     return this._shape
1995 2073
   }
1996 2074
 
1997 2075
   /**
1998 2076
    * The shape's current point.
2077
+   *
2078
+   * \`\`\`ts
2079
+   * const shapePoint = shape.point()
2080
+   * \`\`\`
1999 2081
    */
2000 2082
   get point(): number[] {
2001 2083
     return [...this.shape.point]
2002 2084
   }
2003 2085
 
2004 2086
   set point(point: number[]) {
2005
-    getShapeUtils(this.shape).translateTo(this._shape, point)
2087
+    this.utils.translateTo(this._shape, point)
2088
+  }
2089
+
2090
+  /**
2091
+   * The shape's current x position.
2092
+   *
2093
+   * \`\`\`ts
2094
+   * const shapeX = shape.x
2095
+   *
2096
+   * shape.x = 100
2097
+   * \`\`\`
2098
+   */
2099
+  get x(): number {
2100
+    return this.point[0]
2101
+  }
2102
+
2103
+  set x(x: number) {
2104
+    this.utils.translateTo(this._shape, [x, this.y])
2105
+  }
2106
+
2107
+  /**
2108
+   * The shape's current y position.
2109
+   *
2110
+   * \`\`\`ts
2111
+   * const shapeY = shape.y
2112
+   *
2113
+   * shape.y = 100
2114
+   * \`\`\`
2115
+   */
2116
+  get y(): number {
2117
+    return this.point[1]
2118
+  }
2119
+
2120
+  set y(y: number) {
2121
+    this.utils.translateTo(this._shape, [this.x, y])
2006 2122
   }
2007 2123
 
2008 2124
   /**
2009 2125
    * The shape's rotation.
2126
+   *
2127
+   * \`\`\`ts
2128
+   * const shapeRotation = shape.rotation
2129
+   *
2130
+   * shape.rotation = Math.PI / 2
2131
+   * \`\`\`
2010 2132
    */
2011 2133
   get rotation(): number {
2012 2134
     return this.shape.rotation
2013 2135
   }
2014 2136
 
2015 2137
   set rotation(rotation: number) {
2016
-    getShapeUtils(this.shape).rotateTo(
2017
-      this._shape,
2018
-      rotation,
2019
-      rotation - this.shape.rotation
2020
-    )
2138
+    this.utils.rotateTo(this._shape, rotation, rotation - this.shape.rotation)
2021 2139
   }
2022 2140
 
2023 2141
   /**
2024
-   * The shape's color style.
2142
+   * The shape's color style (ColorStyle).
2143
+   *
2144
+   * \`\`\`ts
2145
+   * const shapeColor = shape.color
2146
+   *
2147
+   * shape.color = ColorStyle.Red
2148
+   * \`\`\`
2025 2149
    */
2026 2150
   get color(): ColorStyle {
2027 2151
     return this.shape.style.color
2028 2152
   }
2029 2153
 
2030 2154
   set color(color: ColorStyle) {
2031
-    getShapeUtils(this.shape).applyStyles(this._shape, { color })
2155
+    this.utils.applyStyles(this._shape, { color })
2032 2156
   }
2033 2157
 
2034 2158
   /**
2035
-   * The shape's dash style.
2159
+   * The shape's dash style (DashStyle).
2160
+   *
2161
+   * \`\`\`ts
2162
+   * const shapeDash = shape.dash
2163
+   *
2164
+   * shape.dash = DashStyle.Dotted
2165
+   * \`\`\`
2036 2166
    */
2037 2167
   get dash(): DashStyle {
2038 2168
     return this.shape.style.dash
2039 2169
   }
2040 2170
 
2041 2171
   set dash(dash: DashStyle) {
2042
-    getShapeUtils(this.shape).applyStyles(this._shape, { dash })
2172
+    this.utils.applyStyles(this._shape, { dash })
2043 2173
   }
2044 2174
 
2045 2175
   /**
2046
-   * The shape's stroke width.
2176
+   * The shape's size (SizeStyle).
2177
+   *
2178
+   * \`\`\`ts
2179
+   * const shapeSize = shape.size
2180
+   *
2181
+   * shape.size = SizeStyle.Large
2182
+   * \`\`\`
2047 2183
    */
2048
-  get strokeWidth(): SizeStyle {
2184
+  get size(): SizeStyle {
2049 2185
     return this.shape.style.size
2050 2186
   }
2051 2187
 
2052
-  set strokeWidth(size: SizeStyle) {
2053
-    getShapeUtils(this.shape).applyStyles(this._shape, { size })
2188
+  set size(size: SizeStyle) {
2189
+    this.utils.applyStyles(this._shape, { size })
2054 2190
   }
2055 2191
 
2056 2192
   /**
2057 2193
    * The shape's index in the painting order.
2194
+   *
2195
+   * \`\`\`ts
2196
+   * const shapeChildIndex = shape.childIndex
2197
+   *
2198
+   * shape.childIndex = 10
2199
+   * \`\`\`
2058 2200
    */
2059 2201
   get childIndex(): number {
2060 2202
     return this.shape.childIndex
2061 2203
   }
2062 2204
 
2063 2205
   set childIndex(childIndex: number) {
2064
-    getShapeUtils(this.shape).setProperty(this._shape, 'childIndex', childIndex)
2206
+    this.utils.setProperty(this._shape, 'childIndex', childIndex)
2207
+  }
2208
+
2209
+  /**
2210
+   * The shape's center.
2211
+   *
2212
+   * \`\`\`ts
2213
+   * const shapeCenter = shape.center
2214
+   *
2215
+   * shape.center = [100, 100]
2216
+   * \`\`\`
2217
+   */
2218
+  get center(): number[] {
2219
+    return this.utils.getCenter(this.shape)
2220
+  }
2221
+
2222
+  set center(center: number[]) {
2223
+    const oldCenter = this.utils.getCenter(this.shape)
2224
+    const delta = Vec.sub(center, oldCenter)
2225
+    this.translateBy(delta)
2065 2226
   }
2066 2227
 }
2067 2228
 
@@ -2117,13 +2278,39 @@ interface ShapeUtility<K extends Shape> {
2117 2278
     })
2118 2279
   }
2119 2280
 
2281
+  /**
2282
+   * The ellipse's x radius.
2283
+   *
2284
+   * \`\`\`ts
2285
+   * const shapeRadiusX = shape.radiusX
2286
+   *
2287
+   * shape.radiusX = 100
2288
+   * \`\`\`
2289
+   */
2120 2290
   get radiusX(): number {
2121 2291
     return this.shape.radiusX
2122 2292
   }
2123 2293
 
2294
+  set radiusX(radiusX: number) {
2295
+    this.utils.setProperty(this.shape, 'radiusX', radiusX)
2296
+  }
2297
+
2298
+  /**
2299
+   * The ellipse's y radius.
2300
+   *
2301
+   * \`\`\`ts
2302
+   * const shapeRadiusY = shape.radiusY
2303
+   *
2304
+   * shape.radiusY = 100
2305
+   * \`\`\`
2306
+   */
2124 2307
   get radiusY(): number {
2125 2308
     return this.shape.radiusY
2126 2309
   }
2310
+
2311
+  set radiusY(radiusY: number) {
2312
+    this.utils.setProperty(this.shape, 'radiusY', radiusY)
2313
+  }
2127 2314
 }
2128 2315
 
2129 2316
 
@@ -2154,9 +2341,21 @@ interface ShapeUtility<K extends Shape> {
2154 2341
     })
2155 2342
   }
2156 2343
 
2344
+  /**
2345
+   * The line's direction.
2346
+   *
2347
+   * \`\`\`ts
2348
+   * const shapeDirection = shape.direction
2349
+   *
2350
+   * shape.direction = [0,0]
2351
+   * \`\`\`
2352
+   */
2157 2353
   get direction(): number[] {
2158 2354
     return this.shape.direction
2159 2355
   }
2356
+  set direction(direction: number[]) {
2357
+    this.utils.setProperty(this.shape, 'direction', direction)
2358
+  }
2160 2359
 }
2161 2360
 
2162 2361
 
@@ -2186,9 +2385,34 @@ interface ShapeUtility<K extends Shape> {
2186 2385
     })
2187 2386
   }
2188 2387
 
2388
+  /**
2389
+   * Add a point to the polyline's points.
2390
+   *
2391
+   * \`\`\`ts
2392
+   * shape.addPoint([100,100])
2393
+   * \`\`\`
2394
+   */
2395
+  addPoint(point: number[]): CodeShape<PolylineShape> {
2396
+    this.utils.setProperty(this.shape, 'points', [...this.points, point])
2397
+    return this
2398
+  }
2399
+
2400
+  /**
2401
+   * The polyline's points.
2402
+   *
2403
+   * \`\`\`ts
2404
+   * const shapePoints = shape.points
2405
+   *
2406
+   * shape.points = [[0,0], [100,100], [100,200]]
2407
+   * \`\`\`
2408
+   */
2189 2409
   get points(): number[][] {
2190 2410
     return this.shape.points
2191 2411
   }
2412
+
2413
+  set points(points: number[][]) {
2414
+    this.utils.setProperty(this.shape, 'points', points)
2415
+  }
2192 2416
 }
2193 2417
 
2194 2418
 
@@ -2219,9 +2443,21 @@ interface ShapeUtility<K extends Shape> {
2219 2443
     })
2220 2444
   }
2221 2445
 
2446
+  /**
2447
+   * The ray's direction.
2448
+   *
2449
+   * \`\`\`ts
2450
+   * const shapeDirection = shape.direction
2451
+   *
2452
+   * shape.direction = [0,0]
2453
+   * \`\`\`
2454
+   */
2222 2455
   get direction(): number[] {
2223 2456
     return this.shape.direction
2224 2457
   }
2458
+  set direction(direction: number[]) {
2459
+    this.utils.setProperty(this.shape, 'direction', direction)
2460
+  }
2225 2461
 }
2226 2462
 
2227 2463
 
@@ -2283,6 +2519,15 @@ interface ShapeUtility<K extends Shape> {
2283 2519
     })
2284 2520
   }
2285 2521
 
2522
+  /**
2523
+   * The arrow's start point.
2524
+   *
2525
+   * \`\`\`ts
2526
+   * const startPoint = shape.start
2527
+   *
2528
+   * shape.start = [100, 100]
2529
+   * \`\`\`
2530
+   */
2286 2531
   get start(): number[] {
2287 2532
     return this.shape.handles.start.point
2288 2533
   }
@@ -2293,6 +2538,15 @@ interface ShapeUtility<K extends Shape> {
2293 2538
     })
2294 2539
   }
2295 2540
 
2541
+  /**
2542
+   * The arrow's middle point.
2543
+   *
2544
+   * \`\`\`ts
2545
+   * const middlePoint = shape.middle
2546
+   *
2547
+   * shape.middle = [100, 100]
2548
+   * \`\`\`
2549
+   */
2296 2550
   get middle(): number[] {
2297 2551
     return this.shape.handles.bend.point
2298 2552
   }
@@ -2303,6 +2557,15 @@ interface ShapeUtility<K extends Shape> {
2303 2557
     })
2304 2558
   }
2305 2559
 
2560
+  /**
2561
+   * The arrow's end point.
2562
+   *
2563
+   * \`\`\`ts
2564
+   * const endPoint = shape.end
2565
+   *
2566
+   * shape.end = [100, 100]
2567
+   * \`\`\`
2568
+   */
2306 2569
   get end(): number[] {
2307 2570
     return this.shape.handles.end.point
2308 2571
   }
@@ -2366,7 +2629,6 @@ interface ShapeUtility<K extends Shape> {
2366 2629
       isHidden: false,
2367 2630
       text: 'Text',
2368 2631
       scale: 1,
2369
-      fontSize: FontSize.Medium,
2370 2632
       ...props,
2371 2633
       style: {
2372 2634
         ...defaultStyle,
@@ -2374,6 +2636,40 @@ interface ShapeUtility<K extends Shape> {
2374 2636
       },
2375 2637
     })
2376 2638
   }
2639
+
2640
+  /**
2641
+   * The text shape's text content.
2642
+   *
2643
+   * \`\`\`ts
2644
+   * const shapeText = shape.text
2645
+   *
2646
+   * shape.text = "Hello world!"
2647
+   * \`\`\`
2648
+   */
2649
+  get text(): string {
2650
+    return this.shape.text
2651
+  }
2652
+
2653
+  set text(text: string) {
2654
+    getShapeUtils(this.shape).setProperty(this.shape, 'text', text)
2655
+  }
2656
+
2657
+  /**
2658
+   * The text's scale.
2659
+   *
2660
+   * \`\`\`ts
2661
+   * const shapeScale = shape.scale
2662
+   *
2663
+   * shape.scale = 2
2664
+   * \`\`\`
2665
+   */
2666
+  get scale(): number {
2667
+    return this.shape.scale
2668
+  }
2669
+
2670
+  set scale(scale: number) {
2671
+    getShapeUtils(this.shape).setProperty(this.shape, 'scale', scale)
2672
+  }
2377 2673
 }
2378 2674
 
2379 2675
 
@@ -2404,8 +2700,44 @@ interface ShapeUtility<K extends Shape> {
2404 2700
     })
2405 2701
   }
2406 2702
 
2407
-  get size(): number[] {
2408
-    return this.shape.size
2703
+  /**
2704
+   * The rectangle's width.
2705
+   *
2706
+   * \`\`\`ts
2707
+   * const shapeWidth = shape.width
2708
+   *
2709
+   * shape.width = 100
2710
+   * \`\`\`
2711
+   */
2712
+  get width(): number {
2713
+    return this.shape.size[0]
2714
+  }
2715
+
2716
+  set width(width: number) {
2717
+    getShapeUtils(this.shape).setProperty(this.shape, 'size', [
2718
+      width,
2719
+      this.height,
2720
+    ])
2721
+  }
2722
+
2723
+  /**
2724
+   * The rectangle's height.
2725
+   *
2726
+   * \`\`\`ts
2727
+   * const shapeHeight = shape.height
2728
+   *
2729
+   * shape.height = 100
2730
+   * \`\`\`
2731
+   */
2732
+  get height(): number {
2733
+    return this.shape.size[1]
2734
+  }
2735
+
2736
+  set height(height: number) {
2737
+    getShapeUtils(this.shape).setProperty(this.shape, 'size', [
2738
+      this.width,
2739
+      height,
2740
+    ])
2409 2741
   }
2410 2742
 }
2411 2743
 

+ 3
- 4
scripts/type-gen.js View File

@@ -25,6 +25,7 @@ async function inlineFileContents(path) {
25 25
       /\/\* ----------------- Start Copy Here ---------------- \*\/(.|\n)*$/g
26 26
     )[0]
27 27
     .replaceAll('/* ----------------- Start Copy Here ---------------- */', '')
28
+    .replaceAll('```', '\\`\\`\\`')
28 29
     .replaceAll('export default', '')
29 30
     .replaceAll('export ', '')
30 31
     .replaceAll('vec.', 'Vec.')
@@ -46,16 +47,14 @@ async function copyTypesToFile() {
46 47
   name: "types.ts",
47 48
   content: \`
48 49
 
49
-type Partial<T> = { [P in keyof T]?: T[P]; };
50
-
51
-type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
52
-  
53 50
 type DeepPartial<T> = {
54 51
   [P in keyof T]?: DeepPartial<T[P]>;
55 52
 };
56 53
 
57 54
 ${await inlineFileContents('/types.ts')}
58 55
 
56
+${await inlineFileContents('/types.ts')}
57
+
59 58
 ${await inlineFileContents('/utils/vec.ts')}
60 59
 
61 60
 ${await inlineFileContents('/state/code/utils.ts')}

+ 27
- 0
state/code/arrow.ts View File

@@ -63,6 +63,15 @@ export default class Arrow extends CodeShape<ArrowShape> {
63 63
     })
64 64
   }
65 65
 
66
+  /**
67
+   * The arrow's start point.
68
+   *
69
+   * ```ts
70
+   * const startPoint = shape.start
71
+   *
72
+   * shape.start = [100, 100]
73
+   * ```
74
+   */
66 75
   get start(): number[] {
67 76
     return this.shape.handles.start.point
68 77
   }
@@ -73,6 +82,15 @@ export default class Arrow extends CodeShape<ArrowShape> {
73 82
     })
74 83
   }
75 84
 
85
+  /**
86
+   * The arrow's middle point.
87
+   *
88
+   * ```ts
89
+   * const middlePoint = shape.middle
90
+   *
91
+   * shape.middle = [100, 100]
92
+   * ```
93
+   */
76 94
   get middle(): number[] {
77 95
     return this.shape.handles.bend.point
78 96
   }
@@ -83,6 +101,15 @@ export default class Arrow extends CodeShape<ArrowShape> {
83 101
     })
84 102
   }
85 103
 
104
+  /**
105
+   * The arrow's end point.
106
+   *
107
+   * ```ts
108
+   * const endPoint = shape.end
109
+   *
110
+   * shape.end = [100, 100]
111
+   * ```
112
+   */
86 113
   get end(): number[] {
87 114
     return this.shape.handles.end.point
88 115
   }

+ 26
- 0
state/code/ellipse.ts View File

@@ -26,11 +26,37 @@ export default class Ellipse extends CodeShape<EllipseShape> {
26 26
     })
27 27
   }
28 28
 
29
+  /**
30
+   * The ellipse's x radius.
31
+   *
32
+   * ```ts
33
+   * const shapeRadiusX = shape.radiusX
34
+   *
35
+   * shape.radiusX = 100
36
+   * ```
37
+   */
29 38
   get radiusX(): number {
30 39
     return this.shape.radiusX
31 40
   }
32 41
 
42
+  set radiusX(radiusX: number) {
43
+    this.utils.setProperty(this.shape, 'radiusX', radiusX)
44
+  }
45
+
46
+  /**
47
+   * The ellipse's y radius.
48
+   *
49
+   * ```ts
50
+   * const shapeRadiusY = shape.radiusY
51
+   *
52
+   * shape.radiusY = 100
53
+   * ```
54
+   */
33 55
   get radiusY(): number {
34 56
     return this.shape.radiusY
35 57
   }
58
+
59
+  set radiusY(radiusY: number) {
60
+    this.utils.setProperty(this.shape, 'radiusY', radiusY)
61
+  }
36 62
 }

+ 189
- 38
state/code/index.ts View File

@@ -7,7 +7,8 @@ import {
7 7
   SizeStyle,
8 8
 } from 'types'
9 9
 import { createShape, getShapeUtils } from 'state/shape-utils'
10
-import { setToArray } from 'utils'
10
+import { setToArray, uniqueId } from 'utils'
11
+import Vec from 'utils/vec'
11 12
 
12 13
 export const codeShapes = new Set<CodeShape<Shape>>([])
13 14
 
@@ -26,7 +27,7 @@ function getOrderedShapes() {
26 27
 
27 28
 export default class CodeShape<T extends Shape> {
28 29
   private _shape: Mutable<T>
29
-  private utils: ShapeUtility<T>
30
+  protected utils: ShapeUtility<T>
30 31
 
31 32
   constructor(props: T) {
32 33
     this._shape = createShape(props.type, props) as Mutable<T>
@@ -34,79 +35,130 @@ export default class CodeShape<T extends Shape> {
34 35
     codeShapes.add(this)
35 36
   }
36 37
 
37
-  export(): Mutable<T> {
38
-    return { ...this._shape }
39
-  }
40
-
41 38
   /**
42 39
    * Destroy the shape.
40
+   *
41
+   * ```ts
42
+   * shape.destroy()
43
+   * ```
43 44
    */
44
-  destroy(): void {
45
+  destroy = (): void => {
45 46
     codeShapes.delete(this)
46 47
   }
47 48
 
48 49
   /**
49 50
    * Move the shape to a point.
50
-   * @param delta
51
+   *
52
+   * ```ts
53
+   * shape.moveTo(100,100)
54
+   * ```
51 55
    */
52
-  moveTo(point: number[]): CodeShape<T> {
56
+  moveTo = (point: number[]): CodeShape<T> => {
53 57
     return this.translateTo(point)
54 58
   }
55 59
 
56 60
   /**
57 61
    * Move the shape to a point.
58
-   * @param delta
62
+   *
63
+   * ```ts
64
+   * shape.translateTo([100,100])
65
+   * ```
59 66
    */
60
-  translateTo(point: number[]): CodeShape<T> {
67
+  translateTo = (point: number[]): CodeShape<T> => {
61 68
     this.utils.translateTo(this._shape, point)
62 69
     return this
63 70
   }
64 71
 
65 72
   /**
66 73
    * Move the shape by a delta.
67
-   * @param delta
74
+   *
75
+   * ```ts
76
+   * shape.translateBy([100,100])
77
+   * ```
68 78
    */
69
-  translateBy(delta: number[]): CodeShape<T> {
79
+  translateBy = (delta: number[]): CodeShape<T> => {
70 80
     this.utils.translateTo(this._shape, delta)
71 81
     return this
72 82
   }
73 83
 
74 84
   /**
75 85
    * Rotate the shape.
86
+   *
87
+   * ```ts
88
+   * shape.rotateTo(Math.PI / 2)
89
+   * ```
76 90
    */
77
-  rotateTo(rotation: number): CodeShape<T> {
91
+  rotateTo = (rotation: number): CodeShape<T> => {
78 92
     this.utils.rotateTo(this._shape, rotation, this.shape.rotation - rotation)
79 93
     return this
80 94
   }
81 95
 
82 96
   /**
83 97
    * Rotate the shape by a delta.
98
+   *
99
+   * ```ts
100
+   * shape.rotateBy(Math.PI / 2)
101
+   * ```
84 102
    */
85
-  rotateBy(rotation: number): CodeShape<T> {
103
+  rotateBy = (rotation: number): CodeShape<T> => {
86 104
     this.utils.rotateBy(this._shape, rotation)
87 105
     return this
88 106
   }
89 107
 
90 108
   /**
91 109
    * Get the shape's bounding box.
110
+   *
111
+   * ```ts
112
+   * const bounds = shape.getBounds()
113
+   * ```
92 114
    */
93
-  getBounds(): CodeShape<T> {
115
+  getBounds = (): CodeShape<T> => {
94 116
     this.utils.getBounds(this.shape)
95 117
     return this
96 118
   }
97 119
 
98 120
   /**
99 121
    * Test whether a point is inside of the shape.
122
+   *
123
+   * ```ts
124
+   * const isHit = shape.hitTest()
125
+   * ```
100 126
    */
101
-  hitTest(point: number[]): CodeShape<T> {
127
+  hitTest = (point: number[]): CodeShape<T> => {
102 128
     this.utils.hitTest(this.shape, point)
103 129
     return this
104 130
   }
105 131
 
132
+  /**
133
+   * Duplicate this shape.
134
+   *
135
+   * ```ts
136
+   * const shapeB = shape.duplicate()
137
+   * ```
138
+   */
139
+  duplicate = (): CodeShape<T> => {
140
+    const duplicate = Object.assign(
141
+      Object.create(Object.getPrototypeOf(this)),
142
+      this
143
+    )
144
+
145
+    duplicate._shape = createShape(this._shape.type, {
146
+      ...this._shape,
147
+      id: uniqueId(),
148
+    } as any)
149
+
150
+    codeShapes.add(duplicate)
151
+    return duplicate
152
+  }
153
+
106 154
   /**
107 155
    * Move the shape to the back of the painting order.
156
+   *
157
+   * ```ts
158
+   * shape.moveToBack()
159
+   * ```
108 160
    */
109
-  moveToBack(): CodeShape<T> {
161
+  moveToBack = (): CodeShape<T> => {
110 162
     const sorted = getOrderedShapes()
111 163
 
112 164
     if (sorted.length <= 1) return
@@ -123,8 +175,12 @@ export default class CodeShape<T extends Shape> {
123 175
 
124 176
   /**
125 177
    * Move the shape to the top of the painting order.
178
+   *
179
+   * ```ts
180
+   * shape.moveToFront()
181
+   * ```
126 182
    */
127
-  moveToFront(): CodeShape<T> {
183
+  moveToFront = (): CodeShape<T> => {
128 184
     const sorted = getOrderedShapes()
129 185
 
130 186
     if (sorted.length <= 1) return
@@ -142,8 +198,12 @@ export default class CodeShape<T extends Shape> {
142 198
 
143 199
   /**
144 200
    * Move the shape backward in the painting order.
201
+   *
202
+   * ```ts
203
+   * shape.moveBackward()
204
+   * ```
145 205
    */
146
-  moveBackward(): CodeShape<T> {
206
+  moveBackward = (): CodeShape<T> => {
147 207
     const sorted = getOrderedShapes()
148 208
 
149 209
     if (sorted.length <= 1) return
@@ -164,8 +224,12 @@ export default class CodeShape<T extends Shape> {
164 224
 
165 225
   /**
166 226
    * Move the shape forward in the painting order.
227
+   *
228
+   * ```ts
229
+   * shape.moveForward()
230
+   * ```
167 231
    */
168
-  moveForward(): CodeShape<T> {
232
+  moveForward = (): CodeShape<T> => {
169 233
     const sorted = getOrderedShapes()
170 234
 
171 235
     if (sorted.length <= 1) return
@@ -189,79 +253,166 @@ export default class CodeShape<T extends Shape> {
189 253
   }
190 254
 
191 255
   /**
192
-   * The shape's underlying shape.
256
+   * The shape's underlying shape (readonly).
257
+   *
258
+   * ```ts
259
+   * const underlyingShape = shape.shape
260
+   * ```
193 261
    */
194
-  get shape(): T {
262
+  get shape(): Readonly<T> {
195 263
     return this._shape
196 264
   }
197 265
 
198 266
   /**
199 267
    * The shape's current point.
268
+   *
269
+   * ```ts
270
+   * const shapePoint = shape.point()
271
+   * ```
200 272
    */
201 273
   get point(): number[] {
202 274
     return [...this.shape.point]
203 275
   }
204 276
 
205 277
   set point(point: number[]) {
206
-    getShapeUtils(this.shape).translateTo(this._shape, point)
278
+    this.utils.translateTo(this._shape, point)
279
+  }
280
+
281
+  /**
282
+   * The shape's current x position.
283
+   *
284
+   * ```ts
285
+   * const shapeX = shape.x
286
+   *
287
+   * shape.x = 100
288
+   * ```
289
+   */
290
+  get x(): number {
291
+    return this.point[0]
292
+  }
293
+
294
+  set x(x: number) {
295
+    this.utils.translateTo(this._shape, [x, this.y])
296
+  }
297
+
298
+  /**
299
+   * The shape's current y position.
300
+   *
301
+   * ```ts
302
+   * const shapeY = shape.y
303
+   *
304
+   * shape.y = 100
305
+   * ```
306
+   */
307
+  get y(): number {
308
+    return this.point[1]
309
+  }
310
+
311
+  set y(y: number) {
312
+    this.utils.translateTo(this._shape, [this.x, y])
207 313
   }
208 314
 
209 315
   /**
210 316
    * The shape's rotation.
317
+   *
318
+   * ```ts
319
+   * const shapeRotation = shape.rotation
320
+   *
321
+   * shape.rotation = Math.PI / 2
322
+   * ```
211 323
    */
212 324
   get rotation(): number {
213 325
     return this.shape.rotation
214 326
   }
215 327
 
216 328
   set rotation(rotation: number) {
217
-    getShapeUtils(this.shape).rotateTo(
218
-      this._shape,
219
-      rotation,
220
-      rotation - this.shape.rotation
221
-    )
329
+    this.utils.rotateTo(this._shape, rotation, rotation - this.shape.rotation)
222 330
   }
223 331
 
224 332
   /**
225
-   * The shape's color style.
333
+   * The shape's color style (ColorStyle).
334
+   *
335
+   * ```ts
336
+   * const shapeColor = shape.color
337
+   *
338
+   * shape.color = ColorStyle.Red
339
+   * ```
226 340
    */
227 341
   get color(): ColorStyle {
228 342
     return this.shape.style.color
229 343
   }
230 344
 
231 345
   set color(color: ColorStyle) {
232
-    getShapeUtils(this.shape).applyStyles(this._shape, { color })
346
+    this.utils.applyStyles(this._shape, { color })
233 347
   }
234 348
 
235 349
   /**
236
-   * The shape's dash style.
350
+   * The shape's dash style (DashStyle).
351
+   *
352
+   * ```ts
353
+   * const shapeDash = shape.dash
354
+   *
355
+   * shape.dash = DashStyle.Dotted
356
+   * ```
237 357
    */
238 358
   get dash(): DashStyle {
239 359
     return this.shape.style.dash
240 360
   }
241 361
 
242 362
   set dash(dash: DashStyle) {
243
-    getShapeUtils(this.shape).applyStyles(this._shape, { dash })
363
+    this.utils.applyStyles(this._shape, { dash })
244 364
   }
245 365
 
246 366
   /**
247
-   * The shape's stroke width.
367
+   * The shape's size (SizeStyle).
368
+   *
369
+   * ```ts
370
+   * const shapeSize = shape.size
371
+   *
372
+   * shape.size = SizeStyle.Large
373
+   * ```
248 374
    */
249
-  get strokeWidth(): SizeStyle {
375
+  get size(): SizeStyle {
250 376
     return this.shape.style.size
251 377
   }
252 378
 
253
-  set strokeWidth(size: SizeStyle) {
254
-    getShapeUtils(this.shape).applyStyles(this._shape, { size })
379
+  set size(size: SizeStyle) {
380
+    this.utils.applyStyles(this._shape, { size })
255 381
   }
256 382
 
257 383
   /**
258 384
    * The shape's index in the painting order.
385
+   *
386
+   * ```ts
387
+   * const shapeChildIndex = shape.childIndex
388
+   *
389
+   * shape.childIndex = 10
390
+   * ```
259 391
    */
260 392
   get childIndex(): number {
261 393
     return this.shape.childIndex
262 394
   }
263 395
 
264 396
   set childIndex(childIndex: number) {
265
-    getShapeUtils(this.shape).setProperty(this._shape, 'childIndex', childIndex)
397
+    this.utils.setProperty(this._shape, 'childIndex', childIndex)
398
+  }
399
+
400
+  /**
401
+   * The shape's center.
402
+   *
403
+   * ```ts
404
+   * const shapeCenter = shape.center
405
+   *
406
+   * shape.center = [100, 100]
407
+   * ```
408
+   */
409
+  get center(): number[] {
410
+    return this.utils.getCenter(this.shape)
411
+  }
412
+
413
+  set center(center: number[]) {
414
+    const oldCenter = this.utils.getCenter(this.shape)
415
+    const delta = Vec.sub(center, oldCenter)
416
+    this.translateBy(delta)
266 417
   }
267 418
 }

+ 12
- 0
state/code/line.ts View File

@@ -30,7 +30,19 @@ export default class Line extends CodeShape<LineShape> {
30 30
     })
31 31
   }
32 32
 
33
+  /**
34
+   * The line's direction.
35
+   *
36
+   * ```ts
37
+   * const shapeDirection = shape.direction
38
+   *
39
+   * shape.direction = [0,0]
40
+   * ```
41
+   */
33 42
   get direction(): number[] {
34 43
     return this.shape.direction
35 44
   }
45
+  set direction(direction: number[]) {
46
+    this.utils.setProperty(this.shape, 'direction', direction)
47
+  }
36 48
 }

+ 25
- 0
state/code/polyline.ts View File

@@ -29,7 +29,32 @@ export default class Polyline extends CodeShape<PolylineShape> {
29 29
     })
30 30
   }
31 31
 
32
+  /**
33
+   * Add a point to the polyline's points.
34
+   *
35
+   * ```ts
36
+   * shape.addPoint([100,100])
37
+   * ```
38
+   */
39
+  addPoint(point: number[]): CodeShape<PolylineShape> {
40
+    this.utils.setProperty(this.shape, 'points', [...this.points, point])
41
+    return this
42
+  }
43
+
44
+  /**
45
+   * The polyline's points.
46
+   *
47
+   * ```ts
48
+   * const shapePoints = shape.points
49
+   *
50
+   * shape.points = [[0,0], [100,100], [100,200]]
51
+   * ```
52
+   */
32 53
   get points(): number[][] {
33 54
     return this.shape.points
34 55
   }
56
+
57
+  set points(points: number[][]) {
58
+    this.utils.setProperty(this.shape, 'points', points)
59
+  }
35 60
 }

+ 12
- 0
state/code/ray.ts View File

@@ -30,7 +30,19 @@ export default class Ray extends CodeShape<RayShape> {
30 30
     })
31 31
   }
32 32
 
33
+  /**
34
+   * The ray's direction.
35
+   *
36
+   * ```ts
37
+   * const shapeDirection = shape.direction
38
+   *
39
+   * shape.direction = [0,0]
40
+   * ```
41
+   */
33 42
   get direction(): number[] {
34 43
     return this.shape.direction
35 44
   }
45
+  set direction(direction: number[]) {
46
+    this.utils.setProperty(this.shape, 'direction', direction)
47
+  }
36 48
 }

+ 39
- 2
state/code/rectangle.ts View File

@@ -2,6 +2,7 @@ import CodeShape from './index'
2 2
 import { uniqueId } from 'utils'
3 3
 import { RectangleShape, ShapeProps, ShapeType } from 'types'
4 4
 import { defaultStyle } from 'state/shape-styles'
5
+import { getShapeUtils } from 'state/shape-utils'
5 6
 
6 7
 /* ----------------- Start Copy Here ---------------- */
7 8
 
@@ -30,7 +31,43 @@ export default class Rectangle extends CodeShape<RectangleShape> {
30 31
     })
31 32
   }
32 33
 
33
-  get size(): number[] {
34
-    return this.shape.size
34
+  /**
35
+   * The rectangle's width.
36
+   *
37
+   * ```ts
38
+   * const shapeWidth = shape.width
39
+   *
40
+   * shape.width = 100
41
+   * ```
42
+   */
43
+  get width(): number {
44
+    return this.shape.size[0]
45
+  }
46
+
47
+  set width(width: number) {
48
+    getShapeUtils(this.shape).setProperty(this.shape, 'size', [
49
+      width,
50
+      this.height,
51
+    ])
52
+  }
53
+
54
+  /**
55
+   * The rectangle's height.
56
+   *
57
+   * ```ts
58
+   * const shapeHeight = shape.height
59
+   *
60
+   * shape.height = 100
61
+   * ```
62
+   */
63
+  get height(): number {
64
+    return this.shape.size[1]
65
+  }
66
+
67
+  set height(height: number) {
68
+    getShapeUtils(this.shape).setProperty(this.shape, 'size', [
69
+      this.width,
70
+      height,
71
+    ])
35 72
   }
36 73
 }

+ 26
- 0
state/code/text.ts View File

@@ -31,6 +31,32 @@ export default class Text extends CodeShape<TextShape> {
31 31
     })
32 32
   }
33 33
 
34
+  /**
35
+   * The text shape's text content.
36
+   *
37
+   * ```ts
38
+   * const shapeText = shape.text
39
+   *
40
+   * shape.text = "Hello world!"
41
+   * ```
42
+   */
43
+  get text(): string {
44
+    return this.shape.text
45
+  }
46
+
47
+  set text(text: string) {
48
+    getShapeUtils(this.shape).setProperty(this.shape, 'text', text)
49
+  }
50
+
51
+  /**
52
+   * The text's scale.
53
+   *
54
+   * ```ts
55
+   * const shapeScale = shape.scale
56
+   *
57
+   * shape.scale = 2
58
+   * ```
59
+   */
34 60
   get scale(): number {
35 61
     return this.shape.scale
36 62
   }

Loading…
Cancel
Save