Skip to content

Commit

Permalink
pulling in mayas documentation (thanks maya)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmalacho-mit committed Jul 24, 2024
1 parent 8e110f5 commit afde318
Show file tree
Hide file tree
Showing 19 changed files with 113 additions and 197 deletions.
6 changes: 3 additions & 3 deletions extensions/documentation/src/anatomy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Extensions are defined by all the files that appear in their associated directory, located within `/extensions/src/`.

This directory is created when you run the command `npm run new:extension <extension name>` from the root of the project, where the value you provide for `<extension name>` is used to name this new directory.
This directory is created when you run the command `pnpm new:extension <extension name>` from the root of the project, where the value you provide for `<extension name>` is used to name this new directory.

> **NOTE:** It is important to keep in mind that the name of an extension's associated directory is internally used to identify it, so it is best to avoid changing the directory's name (as this could affect previously saved `.sb3` projects that reference the extension).
Expand All @@ -24,11 +24,11 @@ Below are the files you should always find within an extension's directory:
- For example, if your extension folder is `myExtension`, you can do the following:
```
cd extensions/myExtension # only do this once
npm run dev
pnpm dev
```
- Instead of running the following from the root of the project every time:
```
npm run dev -- --include myExtension
pnpm dev -i myExtension
```
- Inspect the `package.json` file to see all augmented scripts.

Expand Down
8 changes: 2 additions & 6 deletions extensions/documentation/src/blockUtility/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { BlockUtilityWithID, Environment, block, extension } from "$common";
import { BlockUtilityWithID, Environment, extension, scratch } from "$common";

export default class extends extension({ name: "Block Utility example" }) {
override init(env: Environment) { }

@block({
type: "command",
text: (someArgument) => `Block text with ${someArgument}`,
arg: "number"
})
@(scratch.command`Block text with ${"number"}`)
exampleBlockMethod(someArgument: number, util: BlockUtilityWithID) {
const { blockID } = util;
console.log(`My ID is: ${blockID}`)
Expand Down
10 changes: 5 additions & 5 deletions extensions/documentation/src/customArguments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ One of the coolest is the ability to define custom arguments, which means both:
- Introducing an arbitrary new type of argument
- It could be an alias for a `number` the same way the built-in `Angle` argument is. Or it could be something new entirely, like an object with some specific keys, or an array of a certain length -- whatever you want!
- Defining the UI the allows a user to set / interact with that argument type
- Imagine being able to create argument-specifc UI like is done for the built-in `Note`, `Angle`, `Color`, and `Matrix` arguments
- Imagine being able to create argument-specific UI like is done for the built-in `Note`, `Angle`, `Color`, and `Matrix` arguments

Here's how:

Expand All @@ -17,7 +17,7 @@ For a quick breakdown of how we handle UI generally in the Extension Framework,
Then run the following command:

```bash
npm run add:arg <extension directory>
pnpm add:arg <extension directory>
# For example: npm run add:arg myExtension
```

Expand All @@ -31,7 +31,7 @@ Assume we have the following extension:

[](./extension.ts?export=x)

When invoking the `@block` decorator function on our method that uses a custom argument, we can define the `arg` field like so:
When invoking the `@scratch` decorator function on our method that uses a custom argument, we can define the placeholder like so (note the use of the `instance` parameter in invoking the `makeCustomArgument` function):

[](./index.ts?export=x)

Expand Down Expand Up @@ -63,10 +63,10 @@ At the heart of this implementation is co-opting the usage of block argument's d

> In the extension framework, an argument with a dynamic menu looks like:
>```ts
>arg: {
>@(scratch.command`placholder text ${{
> type: "number",
> options: () => ["option A", "option B"] // for example
>}
>}}`)
>```
This is the perfect setup for our solution, as:
Expand Down
35 changes: 15 additions & 20 deletions extensions/documentation/src/customArguments/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { codeSnippet, notRelevantToExample } from "documentation";
import { block, extension } from "$common";
import { extension, scratch } from "$common";
import { MyCustomArgument, details } from "./extension";

export const x = codeSnippet();
Expand All @@ -10,25 +10,20 @@ import MyArgUI from "./MyArgUI.svelte";
export default class ExtensionWithCustomArgument extends extension(details, "customArguments") {
init = notRelevantToExample;

@block((self) => ({
type: "command",
text: (arg) => `Set custom argument ${arg}`,

/** Invoke the member function `makeCustomArgument` of `self` parameter
* (which is an instance of our `ExtensionWithCustomArgument` class).
* The `makeCustomArgument` function accepts an object with the following fields:
* - component: The `svelte` component that should be displayed when this argument is clicked on.
* - initial: The value that the argument should default to. NOTE that this item has both a 'text' and 'value' field.
* - This is because the value of the custom argument must be able to be represented as a string
* and displayed directly in the block once the UI closes.
* Thus, whenever you set a custom argument, you'll need to provide both a 'value' and a 'text'
* representation of that value.
*/
arg: self.makeCustomArgument({
component: MyArgUI,
initial: { value: { a: 10, b: "Hello world", c: false }, text: "[10, Hello world, false]", }
}),
}))
/** Invoke the member function `makeCustomArgument` of `self` parameter
* (which is an instance of our `ExtensionWithCustomArgument` class).
* The `makeCustomArgument` function accepts an object with the following fields:
* - component: The `svelte` component that should be displayed when this argument is clicked on.
* - initial: The value that the argument should default to. NOTE that this item has both a 'text' and 'value' field.
* - This is because the value of the custom argument must be able to be represented as a string
* and displayed directly in the block once the UI closes.
* Thus, whenever you set a custom argument, you'll need to provide both a 'value' and a 'text'
* representation of that value.
*/
@(scratch.command((instance, $) => $`Set custom argument ${instance.makeCustomArgument({
component: MyArgUI,
initial: { value: { a: 10, b: "Hello world", c: false }, text: "[10, Hello world, false]", }
})}`))
/** Our operation should expect an input that matches our custom argument type */
blockWithCustomArgument(custom: MyCustomArgument) {
const { a, b, c } = custom;
Expand Down
2 changes: 1 addition & 1 deletion extensions/documentation/src/inlineImages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

As noted in [Scratch's extension documentation](https://github.com/scratchfoundation/scratch-vm/blob/develop/docs/extensions.md#adding-an-inline-image), Blocks support arguments that can display images inline within their text display.

We can make use of this feature within the framework by adding an extra argument of type `"inline image"` to our extension's method, and then seperately add an `arg` (or `args`) entry within the associated `@block` decorator invocation.
We can make use of this feature within the framework by adding an extra argument of type `"inline image"` to our extension's method, and then seperately add a placeholder within the associated `@scratch` decorator invocation.

See the below example (which assumes that a file `myPic.png` is located in the same directory as our code):

Expand Down
27 changes: 12 additions & 15 deletions extensions/documentation/src/inlineImages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { codeSnippet } from "documentation";

export const x = codeSnippet();

import { Environment, block, extension } from "$common";
import { Environment, extension, scratch } from "$common";
// We import our image as if it was a code file
import myPic from "./myPic.png";

Expand All @@ -11,29 +11,26 @@ export default class ExampleExtensionWithInlineImages extends extension({
}) {
override init(env: Environment) { }

@block({
type: "command",
text: (image) => `Here's an inline image: ${image}`,
arg: {
@(scratch.command`Here's an inline image: ${
{
type: "image",
uri: myPic,
alt: "this is a test image", // description of the image for screen readers
flipRTL: true,
}
})
}`)
methodWithOnlyInlineImage(image: "inline image") {
// NOTE: The `image` argument should not be used
}

@block({
type: "command",
text: (someNumber, image, someString) => `Here's a number ${someNumber} and picture ${image} and string ${someString}}`,
args: [
{ type: "number" },
{ type: "image", uri: myPic, alt: "this is a test image", flipRTL: true },
"string"
]
})
@(scratch.command`Here's a number ${{ type: "number" }} and picture ${
{
type: "image",
uri: myPic,
alt: "this is a test image",
flipRTL: true
}
} and string ${"string"}}`)
methodWithInlineImageAndOtherArguments(someNumber: number, image: "inline image", someString: string) {
// NOTE: The `image` argument should not be used
}
Expand Down
4 changes: 2 additions & 2 deletions extensions/documentation/src/porting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Here's how:
2. Create your "new" framework-based extension using the command outlined in [Making an Extension](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main#-making-an-extension) and use the ***Extension ID*** you found in step 1 as the value of `<folder to contain extension>`
- For example, if your "old" extension's ***Extension ID*** is `prgRocks` you'll run the following command:
```bash
npm run new:extension prgRocks
pnpm new:extension prgRocks
```
- The reason this is necessary is two-fold: First, in the new extension framework, the name of the folder that contains an extension is automatically used as its ***Extension ID***. Second, because already saved `.sb3` / Scratch projects that use your extension refernce the specific ***Extension ID***, we need to make sure our updated, typescript-based extension has the same ID.
3. Once you have created an extension with a folder name matching the ***Extension ID*** found in step 1, you can actually delete the corresponding entry inside of the `builtinExtensions` object of [scratch-packages/scratch-vm/src/extension-support/extension-manager.js](https://github.com/mitmedialab/prg-extension-boilerplate/blob/main/scratch-packages/scratch-vm/src/extension-support/extension-manager.js)
Expand All @@ -32,7 +32,7 @@ Here's how:
- You can do this as the extension framework will automatically handle adding your extension (and its Extension Menu Display Details) to the [Extension Menu](https://en.scratch-wiki.info/wiki/Extension#Adding_Extensions)
6. Now you can start coding! See the below comparison of a vanilla JS extension class and a typescript / framework based one.
- NOTE: If there's a chance anyone has saved projects with the extension you're porting over, you need to make sure to follow the [Legacy Support](#legacy-support) instructions so those saved projects will continue to load correctly.
7. Once you have migrated all of the "old" ***Impementation*** to your new extension folder & typescript code, you can go ahead and delete the ***Implementation*** folder inside of [pacakges/scratch-vm/src/extensions/](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm/src/extensions).
7. Once you have migrated all of the "old" ***Impementation*** to your new extension folder & typescript code, you can go ahead and delete the ***Implementation*** folder inside of [scratch-packages/scratch-vm/src/extensions/](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm/src/extensions).
8. Now, there should be no remnants of the "old" extension inside of either [scratch-packages/scratch-vm](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-vm) or [scratch-packages/scratch-gui](https://github.com/mitmedialab/prg-extension-boilerplate/tree/main/scratch-packages/scratch-gui) folders, and instead everything lives neatly inside its own directory within [extensions/src](https://github.com/mitmedialab/prg-extension-boilerplate/tree/dev/extensions/src)
9. Test out the project you saved in step 0 to verify that your port worked as expected.

Expand Down
27 changes: 9 additions & 18 deletions extensions/documentation/src/porting/example.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ArgumentType, BlockType, Environment, block, extension } from "$common";
import BlockUtility from "$root/scratch-packages/scratch-vm/src/engine/block-utility";
import { ArgumentType, BlockType, BlockUtilityWithID, Environment, extension, scratch } from "$common";
import formatMessage from './format-message'; // This should actually be an npm package and thus be 'format-message'

const details = {
Expand All @@ -13,22 +12,14 @@ export default class SomeBlocks extends extension(details) {

init(env: Environment) { }

@block({
type: BlockType.Reporter,
args: [
{
type: ArgumentType.String,
defaultValue: 'text',
options: [
{ text: 'Item One', value: 'itemId1' },
'itemId2'
]
},
{ type: ArgumentType.Number, defaultValue: 1 }
],
text: (text, letterNum) => `letter ${letterNum} of ${text}'`,
})
myReporter(text: string, letterNum: number, util: BlockUtility) {
@(scratch.reporter`letter ${
{
type: "string",
defaultValue: 'text',
options: [{ text: 'Item One', value: 'itemId1' },'itemId2']
}
} of ${{ type: "number", defaultValue: 1 }}`)
myReporter(text: string, letterNum: number, util: BlockUtilityWithID) {
const message = formatMessage({
id: 'myReporter.result',
default: 'Letter {letterNum} of {text} is {result}.',
Expand Down
2 changes: 1 addition & 1 deletion extensions/documentation/src/reference/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ sequenceDiagram
participant B as /scratch-packages/scratch-gui/
participant C as /scratch-packages/scratch-vm/
Note over root,C: INITIALIZATION
C-->>B: Lerna utility forces scratch-gui <br>to use /scratch-packages/scratch-vm for its dependency <br>instead of using the external npm package
C-->>B: PNPM tells scratch-gui <br>to use /scratch-packages/scratch-vm for its dependency <br>instead of using the external npm package
Note over root,C: BUILD
Note over root: /scripts/build.ts
activate root
Expand Down
16 changes: 4 additions & 12 deletions extensions/documentation/src/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,23 @@ import { codeSnippet } from "../../";

export const defineExtension = codeSnippet();

import { block, buttonBlock, extension, Environment } from "$common";
import { extension, Environment, scratch } from "$common";

const name = "Extension Under Test";

export default class ExtensionUnderTest extends extension({ name }, "ui") {

init(env: Environment): void { }

@block({
type: "command",
args: ["number", "number"],
text: (x, y) => "placeholder",
})
@(scratch.command`placeholder: ${"number"} and ${"number"}`)
exampleCommand(a: number, b: number) { /* Do something */ }

@block({
type: "reporter",
text: (x) => "placeholder",
arg: "string",
})
@(scratch.reporter`placeholder: ${"string"}`)
exampleReporter(input: string) {
return "Whatever you expect to be the output, given the input"
}

@buttonBlock("placeholder")
@(scratch.button`placeholder`)
exampleButtonThatOpensUI() {
this.openUI("Test");
}
Expand Down
Loading

0 comments on commit afde318

Please sign in to comment.