1
0
Fork 0

wip(markdown): Work on dev docs

This commit is contained in:
Joost De Cock 2022-09-21 09:55:21 +02:00
parent 73f2ed2b52
commit 4aaf078b8a
21 changed files with 1369 additions and 96 deletions

View file

@ -0,0 +1,76 @@
---
title: Part dependencies
---
Dependencies in a part's configuration object are controlled by the `from` and `after` properties.
<Note>
In both cases, you should specify the actual configuration object of the dependency part,
not merely a string with its name.
</Note>
<Tip>
Dependencies configured on parts do not need to be included in the `parts` property
passed to [the Design constructor](/referene/api/design). FreeSewing core will
recursively resolve all dependencies and add them to the design for you.
</Tip>
## after
The `after` property holds an array of parts that should be drafted before the current part:
```js
import { exampleBack } from './back.mjs'
import { exampleFront } from './front.mjs'
const part = {
name: 'example.sleeve',
after: [ exampleBack, exampleFront ],
draft: ({ part }) => part
}
```
The effect of the `after` property is that drafting of this part will be deferred until all the parts listed
in the `after` property are drafted.
<Tip>
If you only have one part for the `after` property, you do not have to specify an array:
```js
import { exampleBack } from './back.mjs'
const part = {
name: 'example.front',
after: exampleBack,
draft: ({ part }) => part
}
```
</Tip>
## from
The `from` property holds a part that should be used as the base for the current part.
In other words, the current part will _extend_ the part listed in `front` and inherit all its content.
```js
import { exampleBack } from './back.mjs'
const part = {
name: 'example.front',
fom: exampleBack,
draft: ({ part }) => part
}
```
<Warning>
Unlike `after`, `front` only ever takes one part since you can only extend one part.
</Warning>

View file

@ -0,0 +1,14 @@
---
title: "Parts: Configuration"
---
Apart from [the `draft()` method](/reference/api/part/draft) a part
can provide the following configuration properties:
- [`name`](/reference/api/part/config/name) __is mandatory__ and holds the part's name
- [`from` and `after`](/reference/api/part/config/dependencies) list the part's dependencies
- [`hide`, `hideDependencies`, or `hideAll`](/reference/api/part/config/hide) hide the part, its dependencies, or both
- [`measurements` and `optionalMeasurements`](/reference/api/part/config/measurements) lists the part's required or optional measurements
- [`options`](/reference/api/part/config/options) lists the part's options
- [`plugins`](/reference/api/part/config/plugins) lists the part's required plugins

View file

@ -0,0 +1,63 @@
---
title: Hiding parts
linktitle: hide, hideDependencies, hideAll
---
The `hide`, `hideDependencies`, and `hideAll` properties on the
part configuration object control the hiding of parts.
<Tip>A hidden part will not be included in the output when it's rendered</Tip>
## hide
To hide the current part, set the `hide` property to a truthy value:
```js
const part = {
name: 'example.front',
hide: true,
draft: ({ part }) => part
}
```
## hideDependencies
When you set the `hideDependencies` property to a truthy value,
all parts that are dependencies of the current part (listed either
in `after` or `from`) will be hidden.
```js
import exampleBase from './base.mjs'
const part = {
name: 'example.front',
from: exampleBbase,
hideDependencies: true,
draft: ({ part }) => part
}
```
## hideAll
When you set the `hideAll` property to a truthy value,
both the current part and all parts that are dependencies of the
current part (listed either in `after` or `from`) will be hidden.
```js
import exampleBase from './base.mjs'
const part = {
name: 'other.base',
from: exampleBbase,
hideAll: true,
draft: ({ part }) => part
}
```
<Note>
This has the same effect as setting both `hide` and `hideDependencies` to
a truthy value.
</Note>

View file

@ -0,0 +1,40 @@
---
title: Part measurements
---
The `measurements` and `optionalMeasurements` properties on the
part configuration object list the part's required and optional
measurements respectively.
<Tip>You should only include what's required by the part itself, not its dependencies</Tip>
## measurements
The `measurements` property should hold the (named of the) measurements
that are required to draft the current part.
```js
const part = {
name: 'example.front',
measurements: [ 'head', 'chest' ],
draft: ({ part }) => part
}
```
## optionalMeasurements
The `optionalMeasurements` property should hold the (named of the) measurements
that are optional to draft the current part.
```js
import { pluginBust } from '@freesewing/plugin-bust'
const part = {
name: 'example.front',
plugins: [ pluginBust ],
measurements: [ 'head', 'chest' ],
optionalMeasurements: [ 'highBust' ],
draft: ({ part }) => part
}
```

View file

@ -0,0 +1,25 @@
---
title: Naming parts
linktitle: name
---
The `name` property is -- together with [the `draft()`
method](/reference/api/part/draft) -- the
only mandatory property in a part's configuration object.
It should hold a string and be unique in the design:
```js
const part = {
name: 'example.front',
draft: ({ part }) => part
}
```
<Tip>
We recommend to use a `design.part` format when naming your part.
This avoids naming clashes when people re-use your parts in other designs.
</Tip>

View file

@ -0,0 +1,37 @@
---
title: Boolean options
---
For options where the choice is either `true` or `false`, **on** or **off**,
or **yes** or **no**, use a boolean option.
## Structure
A boolean option is a plain object with these properties:
- `bool` : Either `true` or `false` which will be the default
<Tip>
Like all options that are configured through an object, you can
add more properties to the options' object to implement functionality on
top of what's provided by the core library.
Refer to [extending options](/reference/api/part/config/options/extend) for
more details.
</Tip>
## Example
```js
const part = {
name: 'example.front',
options: {
withLining: {
bool: true
}
},
draft: ({ part }) => part
}
```

View file

@ -0,0 +1,40 @@
---
title: constant
---
If your option is a scalar value (like a string or a number),
it will be treated as a constant. Constant options are never
exposed in the frontend, but can still be set when using FreeSewing
via the API.
## Structure
Any option holding a scalar value is a constant option.
## Example
```js
const part = {
name: 'example.front',
options: {
collarFactor: 4.8,
fitCollar: false,
},
draft: ({ part }) => part
}
```
<Tip>
##### Why would you use this?
There are typically two use-cases for constant options:
- Rather than define constants in your code, it's good practice to set
them in your configuration file. This way, people who use your
part as a dependency can override them if they would like to.
- A constant option can be used as a feature-flag. Enabling or disabling
parts of the code beyond the control of the end user, but accessible to
developers.
</Tip>

View file

@ -0,0 +1,29 @@
---
title: counter
---
For a given number of things, use a counter option.
Counters are for integers only. Things like number of buttons and so on.
## Structure
Your counter option should be a plain object with these properties:
- `count` : The default integer value
- `min` : The minimal integer value that's allowed
- `max` : The maximum integer value that's allowed
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
## Example
```js
options: {
butttons: {
count: 7,
min: 4,
max: 12
}
}
```

View file

@ -0,0 +1,28 @@
---
title: degrees
---
For angles, use a degree option.
## Structure
Your degree option should be a plain object with these properties:
- `deg` : The default value in degrees
- `min` : The minimul that's allowed
- `max` : The maximum that's allowed
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
## Example
```js
options: {
collarAngle: {
deg: 85,
min: 60
max: 130
}
}
```

View file

@ -0,0 +1,72 @@
---
title: Part options
---
The `options` property on the part configuration object
list the part's options:
```js
const part = {
name: 'example.front',
options: {
chestEase: { pct: 12, min: 0, max: 25 },
},
draft: ({ part }) => part
}
```
## The use case for options
One of the things that sets FreeSewing apart is that sewing patterns are not
static. Each pattern is generated on the spot to accommodate the input
provided by the user. Input that typically includes their measurements.
This _made-to-measure_ approach is sort of _our thing_ at FreeSewing,
but why stop there?
There's a lot of things that can be left up to the user and taken into
consideration when drafting the pattern. Things like how many buttons to use,
whether or not to include pockets, shape of the collar, and so on. The only
limit really is the creativity of the designer.
The `options` section in a part's configuration is what makes this
possible.
## Types of options
These are the types of options supported by the FreeSewing core library:
1. [**boolean** options][bool] are for yes/no choices
2. [**constant** options][const] are used as [feature flags](https://en.wikipedia.org/wiki/Feature_toggle) or to hard-code certain values yet still allow them to be changed when the part is extended
3. [**counter** options][count] are for integer values
4. [**degree** options][deg] are for degrees
5. [**list** options][list] are for a list of possible choices
6. [**millimeter** options][mm] are supported but not recommended (see warning below)
7. [**percentage** options][pct] are for percentages
8. [**snapped percentage** options][snapped] constrain percentage options to (a set of) possible values
<Tip>
In parametric design, percentage options are by far the most common.
They also have the most features and flexibility.
</Tip>
<Warning>
While our core library supports millimeter (`mm`) options,
we do not allow them in designs contributed to FreeSewing.org
as they are a _red flag_ for poor parametric design.
If you believe you need `mm` options, look into [snapped
percentage options](snapped) instead.
</Warning>
[bool]: /reference/api/part/config/options/bool
[const]: /reference/api/part/config/options/const
[count]: /reference/api/part/config/options/counter
[deg]: /reference/api/part/config/options/deg
[list]: /reference/api/part/config/options/list
[pct]: /reference/api/part/config/options/pct
[snapped]: /reference/api/part/config/options/pct/snap
[mm]: /reference/api/part/config/options/pct/mm

View file

@ -0,0 +1,9 @@
---
title: Extending options
---
<Fixme>
Explain extending options here
</Fixme>

View file

@ -0,0 +1,76 @@
---
title: list
---
Use a list option when you want to offer an array of choices.
## Structure
Your list option should be a plain object with these properties:
- `dflt` : The default for this option
- `list` : An array of available values options
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
## Example
```js
options: {
cuffStyle: {
dflt: "angledBarrelCuff",
list: [
"roundedBarrelCuff",
"angledBarrelCuff"
"straightBarrelCuff"
"roundedFrenchCuff"
"angledFrenchCuff"
"straightFrenchCuff"
]
}
}
```
## Suppress translation
In the example above, you want the different `list` options to be translated.
But sometimes, there is no need for that, like in this example from Breanna:
```js
options: {
primaryBustDart: {
list: [
'06:00',
'07:00',
'08:00',
'09:00',
'10:00',
'11:00',
'11:30',
'12:00',
'12:30',
'13:00',
'13:30',
'14:00',
'15:00',
'16:00',
'17:00',
],
dflt: '06:00',
doNotTranslate: true,
},
// More here
}
```
As you can see above, you can set the `doNotTranslate` property to `true` and to indicate this.
<Note>
##### This is not a core feature
To be clear, setting this here does not do anything in core. It's merely extra
metadata you can add on the option to facilitate frontend integration.
</Note>

View file

@ -0,0 +1,52 @@
---
title: millimeter
---
While FreeSewing supports millimeter options, we recommend
using [percentage options][1] and will not accept
contributions that use millimeter options.
## Structure
A millimeter option should be a plain object with these properties:
- `mm` : The default value in millimeter
- `min` : The minimul that's allowed
- `max` : The maximum that's allowed
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
## Example
```js
options: {
elasticWidth: {
mm: 35,
min: 5,
max: 80
}
}
```
<Comment by="joost">
##### What's wrong with millimeter options?
Millimeter options do not scale.
Parametric design is the _raison d'être_ of FreeSewing and that core belief
that things should seamlessly adapt goes out the window when you use a `mm`
option because now you have a value that will not change based on the
input measurements.
You could argue that it's fine because _you can just lower the option_
but that breaks the principle of _sensible defaults_ (aka no surprises).
The fact that you can sidestep the bullet does not mean you're not creating
a footgun.
When you need a millimeter option, reach for a [snapped
percentage option][1] instead.
</Comment>
[1]: /reference/api/config/options/pct

View file

@ -0,0 +1,63 @@
---
title: percentage
---
Percentage options are the bread and butter of freesewing.
Almost all your options will most likely be percentage options as
they ensure that your pattern will scale regardless of size.
## Structure
Your percentage option should be a plain object with these properties:
- `pct` : The default percentage
- `min` : The minimum percentage that's allowed
- `max` : The maximum percentage that's allowed
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
- `fromAbs` <small>(optional)</small> : A method to [determine the percentage based on a value in millimeter][fromabs]
- `toAbs` <small>(optional)</small> : A method to [return the option value in millimeter][toabs]
- `snap` <small>(optional)</small> : The configuration to control [snapping of percentage options][snap]
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
[fromabs]: /reference/api/config/options/pct/fromabs
[toabs]: /reference/api/config/options/pct/toabs
[snap]: /reference/api/config/options/pct/snap
<Note>
###### Percentage options will be divided by 100 when loaded
You specify percentages in your config file. For example, `50` means 50%.
When your configuration is loaded, those percentages will be divided by 100.
So a percentage of `50` in your config file will be `0.5` when you read out that option in your pattern.
###### Percentage options are not limited to the range 0-100
The minimum and maximum (and default) percentages are not restricted to the range from `0%` to `100%`.
A percentage option that spans from `-25%` to `135%` is just as valid.
</Note>
## Example
Below is a simple example:
```js
options: {
acrossBackFactor: {
pct: 97,
min: 93,
max: 100
}
}
```
## Advanced use
Percentage options have a few more tricks up their sleeve:
<ReadMore />

View file

@ -0,0 +1,97 @@
---
title: Setting a value in millimeter as a percentage option
---
Percentage options are great for parametric desing, but not always
very intuitive for the user. For example: A user may desire 13
centimeters (5 inches) of chest ease. But what percentage should
they set the `chestEase` option to to accomplish this?
To address this common grievance, FreeSewing allows you to add a
`fromAbs` method that should take a value in millimeter and
return the percentage the option should be set to to result in this
value.
<Note>
Note that this method will not change the percentage of the option.
It will merely return return a percentage value. It is up to the
frontend designer to then either set this value, or suggest it to
the user.
</Note>
## Structure
The `fromAbs` property should hold a function with the following
signature:
```js
function toAbs(millimeter, settings) {
// return a percentage here (0.5 is 50%)
}
```
The first parameter is the desired value in millimeter (for example
`130` for `13cm`).
The second parameter is the pattern's run-time configuration
or [settings](/reference/api/settings) which holds -- among other things -- the
measurements provided by the user.
## Example
In our example above, let's say that the `chestEase` option is
a simple percentage of the `chest` measurement. Our option
configuration could like like this:
```js
chestEase: {
pct: 8,
min: 0,
max: 20,
fromAbs: function(millimeter, settings) {
return millimeter / settings.measurements.chest
}
}
```
With object destructuring and fat-arrow notation,
you can write it a bit terser like this:
```js
fromAbs: (val, { measurements }) => val /measurements.chest
```
## Using pctBasedOn for simple measurement fractions
Many percentage options represent a simple fraction of a measurement
(chest circumference in the example above).
As this scenario is so common, `@freesewing/core` exports a `pctBasedOn` method
that will do the work for you:
```js
// First import the method
import { pctBasedOn } from '@freesewing/core'
const config = {
// ...
options: {
chestEase: {
pct: 8,
min: 0,
max: 20,
// Pass the measurement name as parameter
// and spread the return value into your option
...pctBasedOn('chest')
}
}
}
```
This will not only add an `fromAbs()` method to your option --
one that will return the percentage of any millimeter value passed into it --
it will also add a `toAbs()` method that does the inverse: return the
value in millimeter of whatever percentage the option is set to.
See [Reporting a percentage option value in
millimeter](/reference/api/config/options/pct/toabs) for details.

View file

@ -0,0 +1,244 @@
---
title: Snapped percentage options
---
Snapped percentage options are a hybrid between [list options][list] and
[percentage options][pct]. By combining traits of both, they create a
sort of _smart list option_ that will select the most appropriate value
from the list, and also allow a pure parametric value if no close match
is found.
## Structure
Your snapped percentage option should be a plain object with these properties:
- `pct` : The default percentage
- `min` : The minimum percentage that's allowed
- `max` : The maximum percentage that's allowed
- `snap`: Holds the snap configuration (see [Snap configuration](#))
- `toAbs`: a method returning the **millimeter value** of the option ([see `toAbs()`][toabs])
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
## Snap configuration
A snapped percentage option requires a `snap` property that will determine
what values to snap to.
There are three different scenarios:
### snap holds a number
When `snap` holds a number, the option will be _snapped_ to a
multiple of this value.
In the example below, the absolute value of this option will be set to a multiple of `7`
(so one of `7`, `14`, `21`, `28`, `35`, ...).
```js
myOption: {
pct:5,
min: 0
max: 35,
snap: 7,
toAbs: (pct, { measurements }) => measurements.waistToFloor * pct
}
```
<Note>
In a case like this, the value will **always** be snapped,
because the snap points will be distributed equally across the entire range
of all possible inputs.
</Note>
### snap holds an array of numbers
When snap holds an array of numbers, the option will be _snapped_ to one of
the numbers unless it's further away than half the distance to its closest neighbor.
In the example below, if the absolute value returned by `toAbs()` is in the
region of influence -- in this example between 4.5 and 69.5 -- the nearest snap value
will be used. If instead it is outside the region of influence, the result of
`toAbs()` will be uses as-is.
```js
myOption: {
pct:5,
min: 0
max: 35,
snap: [7, 12, 21, 34, 53, 64 ]
toAbs: (pct, { measurements }) => measurements.waistToFloor * pct
}
```
### snap is a plain object with `metric` and `imperial` properties that each hold an array of numbers
In this case, the behavior is exaxtle the same as when `snap` holds an array
of numbers.
The differnce is that this allows you to supply a different list of snap values
for users using metric or imperial units.
In the example below, the value of [settings.units](/api/settings/units) will
determine which list of snap values gets used.
Then, if the absolute value returned by `toAbs()` is in the
region of influence -- in this example between 4.5 and 69.5 -- the nearest snap value
will be used. If instead it is outside the region of influence, the result of
`toAbs()` will be uses as-is.
```js
myOption: {
pct:5,
min: 0
max: 35,
snap: {
metric: [7, 12, 21, 34, 53, 64 ],
imperial: [25.4, 50.8, 76.3 ],
}
}
```
<Comment by="joost">
##### Read on for an in-depth look at snapped percentage options
While this information above tells you how to use snapped percentage options,
it does not explain why or when you should use them, or how they work.
Read on if you'd like to learn more about that.
</Comment>
## Example use-case
To understand the need that snapped percentage options are addressing,
we'll use an example use-case: We'll be designing a pajama pants pattern
with an elasticated waist.
In our design, the `waistbandWidth` option should match the width of the
elastic we're going to use so we can construct the waistband accordingly.
We have a few different ways we can approach this:
### Approach A: We use a percentage option
We use a percentage option based on a vertical measurement, like
`waistToFloor`.
The elastic width people end up with is something like 34.12mm for
user A and 27.83mm for user B.
Those are not widths for sale in the store, so that's not great.
### Approach B: We use a list option
We use a list option with a selection of standard elastic
widths to choose from: from half and inch to 3 inches
in 0.5 inch increments.
User A is a doll enthusiasts and 0.5 inch is too big.
User B is working on a giant to go on a float in a parade, and 3 inch
is way too small.
While it would probably work for most people somewhat in the middle,
our solution does not scale.
### Approach C: We use a snapped percentage option
We combine approaches A and B and configure a snapped percentage option
with:
- A percentage based on `waistToFloor`
- Our list of standard elastic widths as _snaps_
For typical humans, our options will _snap_ to the closest match in our
list and behave just like Approach A (with a list option).
For dolls and giants, the option will revert to the parametric value and
behave just like Approach B (with a percentage option).
Sweet!
## How snapped percentage options work
Before we wade into the details, let's first agree on terminology:
- The **percentage value** is the page passed by the user for the option.
Its value always represents a percentage.
- The **millimeter value** is the result of feeding the **percentage value** to
the `toAbs()` method. Its value always represents millimeters.
- The **snap values** are the values provided by the snap confguration.
Each of the values always represents millimeters.
Under the hood, and snapped percentage option will:
- Use `toAbs()` to calculate the **millimeter value** from the **percentage value**
- See whether the **millimeter value** approaches one of the **snap values**
- If so, use the snap value (in millimeter) as provided by one of the **snap values**
- If not, use the **millimeter value** as-is
If you're head's spinning, here's an image that will hopefully clarify things a bit:
![A visual guide to how snapped percentage options work](snap.png)
The gradient box represents the range of any given measurement,
from dolls all the way on the left, to giants all the way on the right.
The sort of middle green-colored region is what the designer had in mind
when designing the pattern, and they have set up snap values -- marked by
a red dot -- for values that they feel make sense.
The region of influence of any given snap point will extend 50% towards its
neighbor on both sides (indicated by the dashed lines).This means that the
region of snap points is continuous, once you're in, you're going to be
snapped to one of the snap points.
However, when you venture out into the area where the designer did not
configure any snap points, the absolute value will be used as-is, without
snapping, just as it would in a normal percentage option.
This system results in the best of both worlds:
- Things like elastic widths and so on can be configured to be fixed values,
of common elastic widths for example
- The absolute value will still scale up and down, but will snap to the closest
fixed value when appropriate.
- When the input measurements go somewhere the designer did not anticipate,
the option will just behave as a regular percentage option
## Using snapped percentage options in your pattern code
This is all well and good, but how do you use this?
Well, just like you can get the `options` object from our shorthand call,
you can now get the `absoluteOptions` object that holds absolute values
for those options with snaps configured.
In our paco example, what used to be:
```js
store.set('ankleElastic', measurements.waistToFloor * options.ankleElastic)
```
is now:
```js
store.set('ankleElastic', absoluteOptions.ankleElastic)
```
<Note>
There's really no added value in setting this in the store as `absoluteOptions`
is available everywhere, but we've changed as little as possible in the example
to clarify the difference.
</Note>
[toabs]: /reference/api/config/options/pct/toabs
[pct]: /reference/api/config/options/pct
[list]: /reference/api/config/options/list
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View file

@ -0,0 +1,86 @@
---
title: Reporting a percentage option value in millimeter
---
Percentage options are great for parametric desing, but not always
very intuitive for the user. For example: Setting the `chestEase`
option to `9%` is not very meaningful unless you happen to know
what that percentage is based on.
To address this common grievance, FreeSewing allows you to add a
`toAbs` method that should return the value of the option in
millimeter.
## Structure
The `toAbs` property should hold a function with the following
signature:
```js
function toAbs(percentage, settings) {
// return value in millimeter here
}
```
The first parameter is the percentage value provided by the user (for example
`0.5` for `50%`).
The second parameter is the pattern's run-time configuration
or [settings](/reference/api/settings) which holds -- among other things -- the
measurements provided by the user.
## Example
In our example above, let's say that the `chestEase` option is
a simple percentage of the `chest` measurement. Our option
configuration could like like this:
```js
chestEase: {
pct: 8,
min: 0,
max: 20,
toAbs: function(value, settings) {
return settings.measurements.chest * value
}
}
```
With object destructuring and fat-arrow notation,
you can write it a bit terser like this:
```js
toAbs: (val, { measurements }) => measurements.chest * val
```
## Using pctBasedOn for simple measurement fractions
Many percentage options represent a simple fraction of a measurement
(chest circumference in the example above).
As this scenario is so common, `@freesewing/core` exports a `pctBasedOn` method
that will do the work for you:
```js
// First import the method
import { pctBasedOn } from '@freesewing/core'
const config = {
// ...
options: {
chestEase: {
pct: 8,
min: 0,
max: 20,
// Pass the measurement name as parameter
// and spread the return value into your option
...pctBasedOn('chest')
}
}
}
```
This will not only add an `toAbs()` method to your option -- one that will return
the value in millimeter of whatever percentage the option is set to -- it will
also add a `fromAbs()` method that does the inverse: return the percentage of
any millimeter value passed into it. See [Setting a value in millimeter as a
percentage option](/api/config/options/pct/fromabs) for details.

View file

@ -0,0 +1,67 @@
---
title: Part plugins
---
The `plugins` property on the part configuration object
list the plugins that are used in/required by the part:
```js
import { pluginBundle } from '@freesewing/plugin-bundle'
import { pluginBust } from '@freesewing/plugin-bust'
const part = {
name: 'example.front',
plugins: [ pluginBundle, pluginBust ],
draft: ({ part }) => part
}
```
<Tip>
You should only list the plugins that required by the part itself,
not those required by its dependencies
</Tip>
## Passing data to a plugin
Some plugins require you to pass data to the plugin.
For these, pass an `[plugin, data]` array:
```js
import { pluginBundle } from '@freesewing/plugin-bundle'
import { myDataPlugin } from 'myDataPlugin'
const myData = {
some: 'data'
}
const part = {
name: 'example.front',
plugins: [ pluginBundle, [ myDataPlugin, data ] ],
draft: ({ part }) => part
}
```
## Conditional plugins
A conditional plugin is loaded conditionally. It should be provided
as an object with the following structure:
```js
import myPlugin from './my-plugin.mjs'
const plugin = {
plugin,
condition,
}
```
Where `plugin` is the plugin itself, and `condition` is the
method to determing whether or not to load it.
<Related>
Refer to [the plugin guide](/guides/plugins) to learn
about conditional plugins
</Related>

View file

@ -0,0 +1,229 @@
---
title: "Parts: The `draft()` method"
---
A `Part` in FreeSewing holds all data, logic, and configuration of a Design.
Parts truly are the building blocks of FreeSewing as they not only provide
the configurarion, but also a `draft()` method that does the actual work
of drafting a parametric design.
## Part structure
A part is an object with the following properties:
| Property | Description |
| -------- | ----------- |
| `draft` | The method that will draft the part (__required__) |
| `measurements` | An array of required measurements |
| `optionalMeasurements` | An array of optional measurements |
| `options` | An object of options |
| `plugins` | A plugin or array of plugins |
## A part's `draft()` method
Each part **must** have a `draft` property that holds a method that will draft the part.
The method's signature is as follows:
```js
function draft(props)
```
The method received a single parameter, an object which you can _destructure_ to
access the following properties:
- [Content constructors](#content-constructors)
- `Path`
- `Point`
- `Snippet`
- [Content containers](#content-constainers)
- `paths`
- `points`
- `snippets`
- [The `macro` runner](#the-macro-runner)
- [Access to settings](#access-to-settings)
- `absoluteOptions`
- `complete`
- `measurements`
- `options`
- `paperless`
- `sa`
- `scale`
- [Top-level methods](#access-to-settings)
- `units()`
- `hide()`
- `unhide()`
- [Utilities](#utilities)
- [Logging via the `log` object](#logging-via-the-log-object)
- [The `store`](#the-store)
- [The `part` object which you must return](#the-part-object-which-you-must-return)
### Content constructors
There are three things you can add to a part: points, paths and snippets.
For each of those, you receive the relevant constructor:
| Property | Description |
| --------:| ----------- |
| `Path` | A [Path constructor](/reference/api/path) to create new paths |
| `Point` | A [Point constructor](/reference/api/point) to create new points |
| `Snippet` | A [Snippet constructor](/reference/api/snippet) to create new snippets |
for example:
```js
new Point(19, 80)
```
### Content containers
Creating a Point, Path, or Snippet by itself doesn't do much.
To add them to your part, assign them to the relevant container object:
| Property | Description |
| --------:| ----------- |
| `paths` | Add a Path to your part by storing it in this container object |
| `points` | The part's points container |
| `snippets` | The part's snippets container |
for example:
```js
points.example = new Point(19, 80)
```
### The `macro` runner
| Property | Description |
| --------:| ----------- |
| `macro` | The macro runner. See [the macros documentation](/reference/macros/) |
for example:
```js
points.title = new Point(100,100)
macro('title', {
at: points.title,
nr: 1,
title: 'front'
})
```
### Access to settings
The (relevant entries of the) `settings` object as by the user are also available:
| Property | Description |
| --------:| ----------- |
| `absoluteOptions` | FIXME |
| `complete` | Access to `settings.complete` |
| `measurements` | Access to `settings.measurements` |
| `options` | Access to `settings.options` |
| `paperless` | Access to `settings.paperless` |
| `sa` | Access to `settings.sa` |
| `scale` | Access to `settings.scale` |
for example:
```js
points.example = new Point(19, measurements.head)
```
### Top-level methods
There's a couple of top-level methods that you can use:
| Property | Description |
| --------:| ----------- |
| `units` | An instance of `utils.units` preconfigured with `settings.units` |
| `hide` | Call `hide()` to hide the part |
| `unhide` | Call `unhide()` to unhide/reveal the part |
for example:
```js
console.log(`123mm is ${units(123)}`)
hide()
```
### Utilities
| Property | Description |
| --------:| ----------- |
| `utils` | A [Utils](/reference/api/utils) instance with utility methods |
for example:
```
points.example = new Point(
measurements.head * utils.stretchToScale(options.stretch),
0
)
```
### Logging via the `log` object
| Property | Description |
| --------:| ----------- |
| `log` | The default logging object from the store (FIXME) |
The `log` object has methods attached to it with the following signature:
```js
function loglevel(string msg)
```
The different log levels are: `debug`, `info`, `warning`, and `error`.
For example:
```js
log.info('Hello')
```
### The store
| Property | Description |
| --------:| ----------- |
| `store` | Holds the [Store](/reference/api/store) instance that is shared across parts |
The store is how you can share data between parts. For example:
```js
store.set('example', 12)
// In some other part
let value = store.get('example') // (value now holds 12)
```
### The `part` object which you must return
| Property | Description |
| --------:| ----------- |
| `part` | The part container itself. **You must return this** |
Last but not least, there is the `part` object which you must return:
```js
// Do clever things here
return part
```
## A part's `measurements` list
The `measurements` property should hold a list (an array) of all the measurements that are required for your part.
For example:
```js
const part = {
draft: ({ part }) => part, // Obviously this is silly
measurements: [ 'head', 'chest', 'waist' ]
}
```
<Note>
You only need to include the measurements required for this part. Not the measurements for any dependencies.
## A part's `optionalMeasurements` list
## A part's `options` list
## A part's `plugin` list

View file

@ -8,104 +8,30 @@ Parts truly are the building blocks of FreeSewing as they not only provide
the configurarion, but also a `draft()` method that does the actual work
of drafting a parametric design.
## Part structure
A part is an object with the following properties:
| Property | Description |
| -------- | ----------- |
| `draft` | The method that will draft the part (__required__) |
| `measurements` | An array of required measurements |
| `optionalMeasurements` | An array of optional measurements |
| `options` | An object of options |
| `plugins` | A plugin or array of plugins |
## A part's `draft()` method
Each part **must** have a `draft` property that holds a method that will draft the part.
The method's signature is as follows:
## Example
```js
function draft({
Path,
Point,
Snippet,
absoluteOptions,
complete,
hide,
log,
macro,
measurements,
paperless,
part,
paths,
points,
scale,
snippets,
options,
sa,
store,
units,
unhide,
utils,
})
const part = {
name: 'example.part',
from: otherPart,
after: [ yetAnotherPart, oneMorePart ],
measurements: ['head', 'chest' ],
optionalMeasurements: ['neck'],
options: {
headEase: { pct: 12, min: 5, max: 20 }
}
hide: false,
hideAll: false,
hideDependencies: true,
plugins: [
plugin1,
plugin1,
[ plugin3, dataForPlugin3 ],
]
}
```
The method received a single parameter, an object which you can _destructure_ to
access the following properties:
Click below to learn more about:
### Provided constructors
| Property | Description |
| --------:| ----------- |
| `Path` | A [Path constructor](/reference/api/path) |
| `Point` | A [Point constructor](/reference/api/point) |
| `Snippet` | A [Snippet constructor](/reference/api/snippet) |
### Provided settings
| Property | Description |
| --------:| ----------- |
| `absoluteOptions` | FIXME |
| `complete` | Holds `settings.complete` |
| `measurements` | Holds `settings.measurements` |
| `paperless` | Holds `settings.paperless` |
| `scale` | Holds `settings.scale` |
| `options` | Holds `settings.options` |
| `sa` | Holds `settings.sa` |
### Provided containers
| Property | Description |
| --------:| ----------- |
| `paths` | The part's paths container |
| `points` | The part's points container |
| `snippets` | The part's snippets container |
| `store` | Holds the [Store](/reference/api/store) instance that is shared across parts |
| `utils` | A [Utils](/reference/api/utils) instance with utility methods |
### Provided methods
| Property | Description |
| --------:| ----------- |
| `hide` | Call `hide()` to hide this part |
| `units` | A context-aware version of `utils.units` |
| `unhide` | A context-aware version of `utils.units` |
### Other provided properties
| Property | Description |
| --------:| ----------- |
| `log` | The default logging object from the store (FIXME) |
| `macro` | The macro runner. See [the macros documentation](/reference/macros/) |
| `part` | The part container itself. **You must return this** |
| `store` | Holds the [Store](/reference/api/store) instance that is shared across parts |
| `utils` | A [Utils](/reference/api/utils) instance with utility methods |
## A part's `measurements` list
## A part's `optionalMeasurements` list
## A part's `options` list
## A part's `plugin` list
- [A part's configuration](/reference/api/part/config)
- [A part's `draft()` method](/reference/api/part/draft)