fragment-tools 0.1.1 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -16
- package/package.json +1 -1
- package/src/client/app/modules/Params.svelte +1 -1
- package/src/client/app/stores/props.js +24 -22
- package/src/client/app/triggers/Keyboard.js +1 -1
- package/src/client/app/triggers/MIDI.js +5 -1
- package/src/client/app/ui/Field.svelte +11 -7
- package/src/client/app/ui/FieldTrigger.svelte +12 -7
- package/src/client/app/ui/fields/ButtonInput.svelte +2 -0
- package/src/client/app/ui/fields/CheckboxInput.svelte +2 -0
- package/src/client/app/ui/fields/ColorInput.svelte +124 -80
- package/src/client/app/ui/fields/ImageInput.svelte +2 -0
- package/src/client/app/ui/fields/Input.svelte +7 -1
- package/src/client/app/ui/fields/ListInput.svelte +2 -0
- package/src/client/app/ui/fields/NumberInput.svelte +9 -0
- package/src/client/app/ui/fields/ProgressInput.svelte +2 -0
- package/src/client/app/ui/fields/Select.svelte +2 -0
- package/src/client/app/ui/fields/TextInput.svelte +3 -1
- package/src/client/app/ui/fields/VectorInput.svelte +37 -47
- package/src/client/app/utils/color.utils.js +191 -132
- package/src/client/app/utils/props.utils.js +11 -13
- package/. npmignore +0 -4
- package/docs/README.md +0 -18
- package/docs/api/CLI.md +0 -44
- package/docs/api/renderers.md +0 -80
- package/docs/api/sketch.md +0 -216
- package/docs/api/triggers.md +0 -101
- package/docs/guide/about.md +0 -16
- package/docs/guide/exports.md +0 -86
- package/docs/guide/external-dependencies.md +0 -22
- package/docs/guide/getting-started.md +0 -113
- package/docs/guide/hot-shader-reloading.md +0 -20
- package/docs/guide/shortcuts.md +0 -12
- package/docs/guide/triggers.png +0 -0
- package/docs/guide/using-triggers.md +0 -39
- package/examples/cube-three.js +0 -34
- package/examples/ellipse-p5.js +0 -26
- package/examples/icon.fs +0 -96
- package/examples/icon.js +0 -63
- package/examples/icon.png +0 -0
- package/examples/icon.transparent.png +0 -0
- package/examples/package-lock.json +0 -40
- package/examples/package.json +0 -14
- package/examples/shape-2d.js +0 -50
- package/examples/shape-three.js +0 -49
- package/examples/shape-tree.fs +0 -3
- package/src/client/app/ui/fields/Vec2Input.svelte +0 -5
- package/src/client/app/ui/fields/Vec3Input.svelte +0 -6
package/README.md
CHANGED
|
@@ -17,33 +17,21 @@
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
`fragment` is not yet available on [npmjs.com](npmjs.com) so you need to clone and link the project in order to use it. It's only a few steps.
|
|
21
|
-
|
|
22
20
|
```
|
|
23
|
-
|
|
24
|
-
git clone https://github.com/raphaelameaume/fragment
|
|
25
|
-
|
|
26
|
-
# move to the project directory
|
|
27
|
-
cd fragment
|
|
28
|
-
|
|
29
|
-
# link the project
|
|
30
|
-
npm link
|
|
21
|
+
npm install fragment-tools -g
|
|
31
22
|
```
|
|
32
23
|
|
|
33
|
-
You should now be able to run `fragment` from your command line.
|
|
24
|
+
You should now be able to run `fragment` from your command line.
|
|
34
25
|
|
|
35
26
|
## Usage
|
|
36
27
|
|
|
37
28
|
```
|
|
38
29
|
# create a new directory for your sketches
|
|
39
|
-
mkdir
|
|
30
|
+
mkdir sketches
|
|
40
31
|
|
|
41
32
|
# move into that folder
|
|
42
33
|
cd sketches
|
|
43
34
|
|
|
44
|
-
# initialize npm for linking to work
|
|
45
|
-
npm init
|
|
46
|
-
|
|
47
35
|
# create a sketch from a template
|
|
48
36
|
fragment ./sketch.js --new --template=2d
|
|
49
37
|
```
|
|
@@ -80,7 +68,7 @@ export let update = ({ context, width, height }) => {
|
|
|
80
68
|
};
|
|
81
69
|
```
|
|
82
70
|
|
|
83
|
-
Learn how to write your own sketch
|
|
71
|
+
Learn how to write your own sketch by following the [Getting started](./docs//guide/getting-started.md) guide, reading the [API docs](./docs/api/sketch.md) or the [examples](./examples/).
|
|
84
72
|
|
|
85
73
|
## Contributing
|
|
86
74
|
|
|
@@ -88,6 +76,39 @@ If you find issues, please [file one](https://github.com/raphaelameaume/fragment
|
|
|
88
76
|
|
|
89
77
|
Feel free to reach out on [Twitter](https://twitter.com/raphaelameaume) if you want to discuss the project.
|
|
90
78
|
|
|
79
|
+
## Running it locally
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
# clone or fork the project
|
|
83
|
+
git clone https://github.com/raphaelameaume/fragment.git
|
|
84
|
+
|
|
85
|
+
# move to the root of the repository
|
|
86
|
+
cd fragment
|
|
87
|
+
|
|
88
|
+
# run the command line locally
|
|
89
|
+
node ./bin/index.js examples/shape-2d.js --dev
|
|
90
|
+
|
|
91
|
+
# or from your sketch folder
|
|
92
|
+
node [path-to-root]/bin/index.js sketch.js --dev
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> The `--dev` flag only enables Vite `info` logLevel, helpful for development. Otherwise it will work the same as when you're running from the npm package.
|
|
96
|
+
|
|
97
|
+
Alternatively, you can tell npm to point the `fragment` command to the newly cloned folder.
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
# at the root of the repo
|
|
101
|
+
npm link
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
You should be able the command as before, only this time it will point to the repository instead of the globally installed package.
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
fragment sketch.js
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If that's not the case, try to uninstall `fragment-tools` globally first, make sure the `fragment` command is not found anymore, then retry to link the project from the root of the repo.
|
|
111
|
+
|
|
91
112
|
## Credits
|
|
92
113
|
|
|
93
114
|
- [Vite](https://vitejs.dev/)
|
package/package.json
CHANGED
|
@@ -92,8 +92,8 @@ $: showOutputParams = (monitor && monitor.selected === "output") ||
|
|
|
92
92
|
context={sketchKey}
|
|
93
93
|
key={key}
|
|
94
94
|
value={sketchProps[key].value}
|
|
95
|
-
params={sketchProps[key].params || {}}
|
|
96
95
|
type={sketchProps[key].type}
|
|
96
|
+
bind:params={sketchProps[key].params}
|
|
97
97
|
on:click={() => {
|
|
98
98
|
$props[sketchKey][key].value._refresh = true;
|
|
99
99
|
}}
|
|
@@ -4,41 +4,43 @@ import { sketches } from "./sketches";
|
|
|
4
4
|
export const props = writable({});
|
|
5
5
|
|
|
6
6
|
sketches.subscribe((sketches) => {
|
|
7
|
-
|
|
7
|
+
props.update((currentProps) => {
|
|
8
|
+
Object.keys(sketches).forEach((key) => {
|
|
9
|
+
const sketch = sketches[key];
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
$props[key] = reconcile(sketch.props, $props[key]);
|
|
14
|
-
}
|
|
11
|
+
if (sketch) { // sketch can be undefined if failed to load
|
|
12
|
+
currentProps[key] = reconcile(sketch.props, currentProps[key]);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
15
|
|
|
16
|
+
return currentProps;
|
|
16
17
|
});
|
|
17
|
-
|
|
18
|
-
props.set($props);
|
|
19
18
|
});
|
|
20
19
|
|
|
21
|
-
function reconcile(newProps = {},
|
|
22
|
-
Object.keys(newProps).forEach(propKey => {
|
|
23
|
-
|
|
20
|
+
function reconcile(newProps = {}, prevProps = {}) {
|
|
21
|
+
Object.keys(newProps).forEach((propKey) => {
|
|
22
|
+
let newProp = newProps[propKey];
|
|
23
|
+
|
|
24
|
+
if (!newProp.params) {
|
|
25
|
+
newProp.params = {};
|
|
26
|
+
}
|
|
24
27
|
});
|
|
25
28
|
|
|
26
|
-
if (
|
|
27
|
-
Object.keys(
|
|
29
|
+
if (prevProps) {
|
|
30
|
+
Object.keys(prevProps).forEach((propKey) => {
|
|
31
|
+
let prevProp = prevProps[propKey];
|
|
28
32
|
let newProp = newProps[propKey];
|
|
29
33
|
|
|
30
34
|
if (newProp) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (overrideValue) {
|
|
37
|
-
newProp.value = prevProp.value;
|
|
35
|
+
if (prevProp.params) {
|
|
36
|
+
// reconcile locked VectorInput from UI
|
|
37
|
+
if (prevProp.params.locked !== undefined) {
|
|
38
|
+
newProp.params.locked = prevProp.params.locked;
|
|
39
|
+
}
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
});
|
|
41
|
-
}
|
|
43
|
+
}
|
|
42
44
|
|
|
43
45
|
return newProps;
|
|
44
46
|
}
|
|
@@ -61,7 +61,7 @@ function createTrigger(eventName, collection) {
|
|
|
61
61
|
const { hot, enabled, ...params } = options;
|
|
62
62
|
const context = getContext();
|
|
63
63
|
|
|
64
|
-
const keys = Array.isArray(key) ? key : [key];
|
|
64
|
+
const keys = Array.isArray(key) ? key : [...key.split(',').map(k => k.trim())];
|
|
65
65
|
|
|
66
66
|
const trigger = new Trigger({
|
|
67
67
|
inputType: 'Keyboard',
|
|
@@ -78,7 +78,11 @@ function createTrigger(eventName, collection) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const { hot, enabled, ...params } = options;
|
|
81
|
-
|
|
81
|
+
let keys = Array.isArray(key) ? key : [...key.split(',').map(k => k.trim())];
|
|
82
|
+
|
|
83
|
+
if (["onControlChange", "onNumberOn", "onNumberOff"].includes(eventName)) {
|
|
84
|
+
keys = keys.map((k) => Number(k));
|
|
85
|
+
}
|
|
82
86
|
|
|
83
87
|
if (!MIDI.enabled) {
|
|
84
88
|
MIDI.request();
|
|
@@ -4,8 +4,7 @@ import { createEventDispatcher } from "svelte";
|
|
|
4
4
|
import Select from "./fields/Select.svelte";
|
|
5
5
|
import NumberInput from "./fields/NumberInput.svelte";
|
|
6
6
|
import CheckboxInput from "./fields/CheckboxInput.svelte";
|
|
7
|
-
import
|
|
8
|
-
import Vec3Input from "./fields/Vec3Input.svelte";
|
|
7
|
+
import VectorInput from "./fields/VectorInput.svelte";
|
|
9
8
|
import TextInput from "./fields/TextInput.svelte";
|
|
10
9
|
import ColorInput from "./fields/ColorInput.svelte";
|
|
11
10
|
import ListInput from "./fields/ListInput.svelte";
|
|
@@ -20,7 +19,7 @@ import frameDebounce from "../lib/helpers/frameDebounce.js";
|
|
|
20
19
|
import { getStore } from "../stores/utils";
|
|
21
20
|
import { writable } from "svelte/store";
|
|
22
21
|
|
|
23
|
-
export let key =
|
|
22
|
+
export let key = "";
|
|
24
23
|
export let value = null;
|
|
25
24
|
export let context = null;
|
|
26
25
|
export let params = {};
|
|
@@ -50,8 +49,7 @@ const dispatch = createEventDispatcher();
|
|
|
50
49
|
const fields = {
|
|
51
50
|
"select": Select,
|
|
52
51
|
"number": NumberInput,
|
|
53
|
-
"
|
|
54
|
-
"vec3": Vec3Input,
|
|
52
|
+
"vec": VectorInput,
|
|
55
53
|
"checkbox": CheckboxInput,
|
|
56
54
|
"text": TextInput,
|
|
57
55
|
"list": ListInput,
|
|
@@ -120,7 +118,11 @@ function toggleTriggers(event) {
|
|
|
120
118
|
function composeFieldProps(params) {
|
|
121
119
|
const { triggerable, controllable, ...rest } = params;
|
|
122
120
|
|
|
123
|
-
return
|
|
121
|
+
return {
|
|
122
|
+
...rest,
|
|
123
|
+
key,
|
|
124
|
+
context,
|
|
125
|
+
};
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
</script>
|
|
@@ -149,7 +151,7 @@ function composeFieldProps(params) {
|
|
|
149
151
|
</svg>
|
|
150
152
|
</button>
|
|
151
153
|
{/if}
|
|
152
|
-
{#if (fieldType === "
|
|
154
|
+
{#if (fieldType === "vec") && !disabled }
|
|
153
155
|
<button class="field__action field__action--lock" on:click={() => params.locked = !params.locked}>
|
|
154
156
|
{#if params.locked}
|
|
155
157
|
<svg class="action__icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
|
|
@@ -200,11 +202,13 @@ function composeFieldProps(params) {
|
|
|
200
202
|
|
|
201
203
|
:global(.field__input .field) {
|
|
202
204
|
padding-left: 0px !important;
|
|
205
|
+
padding-right: 0px !important;
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
:global(.field__input .field:last-child) {
|
|
206
209
|
border-bottom: 0px solid #323233 !important;
|
|
207
210
|
padding-bottom: 0px !important;
|
|
211
|
+
|
|
208
212
|
}
|
|
209
213
|
|
|
210
214
|
.field.disabled {
|
|
@@ -72,7 +72,7 @@ function onTypeChange(event) {
|
|
|
72
72
|
|
|
73
73
|
if (!eventOptions.includes(eventName)) {
|
|
74
74
|
eventName = undefined;
|
|
75
|
-
key = null;
|
|
75
|
+
params.key = null;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
if (trigger) {
|
|
@@ -82,19 +82,24 @@ function onTypeChange(event) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function onEventChange(event) {
|
|
85
|
+
const clearParams = (inputType === "MIDI" && eventName !== undefined &&
|
|
86
|
+
((eventName.includes("Number") && event.detail.includes("Note")) ||
|
|
87
|
+
(eventName.includes("Note") && event.detail.includes("Number")))
|
|
88
|
+
);
|
|
89
|
+
|
|
85
90
|
eventName = event.detail;
|
|
86
91
|
|
|
92
|
+
if (clearParams) {
|
|
93
|
+
params.key = "";
|
|
94
|
+
}
|
|
95
|
+
|
|
87
96
|
if (inputType === "Mouse") {
|
|
88
97
|
registerTrigger();
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
function onTextChange(e) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
params.key = e.detail.split(',').map((value) => {
|
|
96
|
-
return castToNumber ? Number(value) : value;
|
|
97
|
-
});
|
|
102
|
+
params.key = e.detail;
|
|
98
103
|
|
|
99
104
|
registerTrigger();
|
|
100
105
|
}
|
|
@@ -153,7 +158,7 @@ $: eventOptions = inputType ? [
|
|
|
153
158
|
] : [];
|
|
154
159
|
|
|
155
160
|
$: isValid = inputType && eventName;
|
|
156
|
-
$: key = params.key
|
|
161
|
+
$: key = params.key;
|
|
157
162
|
|
|
158
163
|
</script>
|
|
159
164
|
|
|
@@ -5,55 +5,53 @@ import TextInput from "./TextInput.svelte";
|
|
|
5
5
|
import Field from "../Field.svelte";
|
|
6
6
|
|
|
7
7
|
export let value;
|
|
8
|
+
export let context = null;
|
|
9
|
+
export let key = "";
|
|
8
10
|
|
|
9
11
|
const dispatch = createEventDispatcher();
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
(
|
|
22
|
-
color.isRGBAString(textValue) ||
|
|
23
|
-
color.isVec4String(textValue) ||
|
|
24
|
-
color.isHSLAString(textValue)
|
|
25
|
-
);
|
|
26
|
-
$: {
|
|
27
|
-
if (isInputDriven) {
|
|
28
|
-
textValue = formatColorFromHex(hexValue);
|
|
29
|
-
} else {
|
|
30
|
-
hexValue = color.toHex(textValue);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (color.isTHREE(value)) {
|
|
34
|
-
const [r, g, b] = color.hexToComponents(hexValue);
|
|
35
|
-
|
|
36
|
-
value.r = r / 255;
|
|
37
|
-
value.g = g / 255;
|
|
38
|
-
value.b = b / 255;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
dispatchChange();
|
|
42
|
-
}
|
|
43
|
-
|
|
13
|
+
$: format = color.getColorFormat(value);
|
|
14
|
+
$: hexValue = color.toHex(value, format);
|
|
15
|
+
$: textValue = color.toString(value, format);
|
|
16
|
+
$: alpha = 1;
|
|
17
|
+
$: hasAlpha = [
|
|
18
|
+
color.FORMATS.RGBA_STRING,
|
|
19
|
+
color.FORMATS.VEC4_STRING,
|
|
20
|
+
color.FORMATS.RGBA_OBJECT,
|
|
21
|
+
color.FORMATS.HSLA_STRING
|
|
22
|
+
].includes(format);
|
|
44
23
|
$: {
|
|
45
24
|
if (hasAlpha) {
|
|
46
|
-
const [r, g, b, a = 1] = color.toComponents(
|
|
25
|
+
const [r, g, b, a = 1] = color.toComponents(value);
|
|
47
26
|
alpha = a;
|
|
27
|
+
} else {
|
|
28
|
+
alpha = 1;
|
|
48
29
|
}
|
|
49
30
|
}
|
|
50
31
|
|
|
51
32
|
function dispatchChange() {
|
|
33
|
+
const [r, g, b] = color.hexToComponents(hexValue);
|
|
34
|
+
|
|
52
35
|
// support THREE.Color
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
switch (format) {
|
|
37
|
+
case color.FORMATS.THREE:
|
|
38
|
+
case color.FORMATS.RGB_OBJECT:
|
|
39
|
+
value.r = r;
|
|
40
|
+
value.g = g;
|
|
41
|
+
value.b = b;
|
|
42
|
+
|
|
43
|
+
dispatch('change', value);
|
|
44
|
+
break;
|
|
45
|
+
case color.FORMATS.RGBA_OBJECT:
|
|
46
|
+
value.r = r;
|
|
47
|
+
value.g = g;
|
|
48
|
+
value.b = b;
|
|
49
|
+
value.a = alpha;
|
|
50
|
+
|
|
51
|
+
dispatch('change', value);
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
dispatch('change', textValue);
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
|
|
@@ -61,58 +59,74 @@ function handleBlur() {
|
|
|
61
59
|
dispatchChange();
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
function formatColorFromHex(hex) {
|
|
65
|
-
if (override) return textValue;
|
|
66
|
-
|
|
67
|
-
if (format === color.FORMATS.THREE) return color.threeToHexString(value);
|
|
68
|
-
if (format === color.FORMATS.HEX_STRING) return hex;
|
|
69
|
-
if (format === color.FORMATS.VEC3_STRING) return color.hexToVec3String(hex);
|
|
70
|
-
if (format === color.FORMATS.RGB_STRING) return color.hexToRGBString(hex);
|
|
71
|
-
|
|
72
|
-
let components = color.hexToComponents(hex);
|
|
73
|
-
|
|
74
|
-
if (hasAlpha && alpha !== 1) {
|
|
75
|
-
components[3] = alpha;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (format === color.FORMATS.HSL_STRING) return color.hexToHSLString(components);
|
|
79
|
-
if (format === color.FORMATS.RGBA_STRING) return color.componentsToRGBAString(components);
|
|
80
|
-
if (format === color.FORMATS.VEC4_STRING) return color.componentsToVec4String(components);
|
|
81
|
-
if (format === color.FORMATS.HSLA_STRING) return color.componentsToHSLAString(components);
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
62
|
function onChangeText(event) {
|
|
86
|
-
isInputDriven = false;
|
|
87
|
-
|
|
88
63
|
const newColor = event.detail;
|
|
89
64
|
|
|
90
65
|
if (color.isColor(newColor)) {
|
|
91
|
-
format = color.getColorFormat(newColor);
|
|
92
66
|
textValue = newColor;
|
|
67
|
+
} else {
|
|
68
|
+
// newColor is not a color, reset value
|
|
69
|
+
textValue = color.toString(value, format);
|
|
93
70
|
}
|
|
71
|
+
|
|
72
|
+
hexValue = color.toHex(textValue);
|
|
73
|
+
dispatchChange();
|
|
94
74
|
}
|
|
95
75
|
|
|
96
76
|
function onChangeAlpha(event) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
77
|
+
alpha = event.detail;
|
|
78
|
+
|
|
79
|
+
const [r, g, b] = color.hexToComponents(hexValue);
|
|
80
|
+
|
|
81
|
+
switch(format) {
|
|
82
|
+
case color.FORMATS.RGBA_STRING:
|
|
83
|
+
case color.FORMATS.RGBA_OBJECT:
|
|
84
|
+
textValue = color.componentsToRGBAString([r, g, b, alpha]);
|
|
85
|
+
break;
|
|
86
|
+
case color.FORMATS.VEC4_STRING:
|
|
87
|
+
textValue = color.componentsToVec4String([r, g, b, alpha]);
|
|
88
|
+
break;
|
|
89
|
+
case color.FORMATS.HSLA_STRING:
|
|
90
|
+
const [h, s, l] = color.hslToHSLComponents(textValue);
|
|
91
|
+
textValue = color.hslaToHSLAString([h, s, l, alpha]);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
105
94
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const [h, s, l] = color.hslToHSLComponents(textValue);
|
|
95
|
+
dispatchChange();
|
|
96
|
+
}
|
|
109
97
|
|
|
110
|
-
|
|
98
|
+
function onInput(event) {
|
|
99
|
+
hexValue = event.currentTarget.value;
|
|
100
|
+
|
|
101
|
+
const [r, g, b] = color.hexToComponents(hexValue);
|
|
102
|
+
|
|
103
|
+
switch(format) {
|
|
104
|
+
case color.FORMATS.RGBA_STRING:
|
|
105
|
+
case color.FORMATS.RGBA_OBJECT:
|
|
106
|
+
textValue = color.toRGBAString({ r, g, b, a: alpha });
|
|
107
|
+
break;
|
|
108
|
+
case color.FORMATS.VEC3_STRING:
|
|
109
|
+
textValue = color.componentsToVec3String([r, g, b]);
|
|
110
|
+
break;
|
|
111
|
+
case color.FORMATS.VEC4_STRING:
|
|
112
|
+
textValue = color.componentsToVec4String([r, g, b, alpha]);
|
|
113
|
+
break;
|
|
114
|
+
case color.FORMATS.RGB_STRING:
|
|
115
|
+
case color.FORMATS.RGB_OBJECT:
|
|
116
|
+
textValue = color.toRGBString(hexValue);
|
|
117
|
+
break;
|
|
118
|
+
case color.FORMATS.HSL_STRING:
|
|
119
|
+
textValue = color.componentsToHSLString([r, g, b]);
|
|
120
|
+
break;
|
|
121
|
+
case color.FORMATS.HSLA_STRING:
|
|
122
|
+
textValue = color.componentsToHSLAString([r, g, b, alpha]);
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
textValue = color.toString(hexValue);
|
|
126
|
+
break;
|
|
111
127
|
}
|
|
112
|
-
}
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
isInputDriven = true;
|
|
129
|
+
dispatchChange();
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
</script>
|
|
@@ -120,13 +134,31 @@ function onInput() {
|
|
|
120
134
|
<div class="color-input">
|
|
121
135
|
<div class="layout">
|
|
122
136
|
<div class="mirror" style="--currentColor: {hexValue}; --opacity: {alpha}">
|
|
137
|
+
{#if hasAlpha }
|
|
138
|
+
<svg width="calc(100% - 2px)" height="calc(100% - 2px)" class="alpha-svg">
|
|
139
|
+
<pattern id="checker" x="0" y="0" width="7.2" height="7.2" patternUnits="userSpaceOnUse">
|
|
140
|
+
<rect fill="white" x="0" width="3.6" height="3.6" y="0"></rect>
|
|
141
|
+
<rect fill="grey" x="3.6" width="3.6" height="3.6" y="0"></rect>
|
|
142
|
+
<rect fill="white" x="3.6" width="3.6" height="3.6" y="3.6"></rect>
|
|
143
|
+
<rect fill="grey" x="0" width="3.6" height="3.6" y="3.6"></rect>
|
|
144
|
+
</pattern>
|
|
145
|
+
<!-- The canvas with our applied pattern -->
|
|
146
|
+
<rect x="0" y="0" width="100%" height="100%" fill="url(#checker)"></rect>
|
|
147
|
+
</svg>
|
|
148
|
+
{/if}
|
|
123
149
|
<!-- svelte-ignore -->
|
|
124
150
|
<input class="input" type="color" bind:value={hexValue} on:blur={handleBlur} on:input={onInput} />
|
|
125
151
|
</div>
|
|
126
|
-
<TextInput value={textValue} on:change={onChangeText} />
|
|
152
|
+
<TextInput {context} {key} bind:value={textValue} on:change={onChangeText} />
|
|
127
153
|
</div>
|
|
128
154
|
{#if hasAlpha }
|
|
129
|
-
<Field
|
|
155
|
+
<Field
|
|
156
|
+
key={`${key}.alpha`}
|
|
157
|
+
value={alpha}
|
|
158
|
+
params={{label: "alpha", min: 0, max: 1, step: 0.01}}
|
|
159
|
+
{context}
|
|
160
|
+
on:change={onChangeAlpha}
|
|
161
|
+
/>
|
|
130
162
|
{/if }
|
|
131
163
|
</div>
|
|
132
164
|
|
|
@@ -143,6 +175,16 @@ function onInput() {
|
|
|
143
175
|
align-items: center;
|
|
144
176
|
}
|
|
145
177
|
|
|
178
|
+
.alpha-svg {
|
|
179
|
+
position: absolute;
|
|
180
|
+
top: 1px;
|
|
181
|
+
left: 1px;
|
|
182
|
+
right: 1px;
|
|
183
|
+
bottom: 1px;
|
|
184
|
+
|
|
185
|
+
border-radius: calc(var(--border-radius-input) * 0.5);
|
|
186
|
+
}
|
|
187
|
+
|
|
146
188
|
.mirror {
|
|
147
189
|
position: relative;
|
|
148
190
|
|
|
@@ -152,11 +194,12 @@ function onInput() {
|
|
|
152
194
|
box-shadow: inset 0 0 0 1px var(--color-border-input);
|
|
153
195
|
}
|
|
154
196
|
|
|
155
|
-
.mirror:
|
|
197
|
+
.mirror:after {
|
|
156
198
|
--gap: 1px;
|
|
157
199
|
|
|
158
200
|
content: '';
|
|
159
201
|
position: absolute;
|
|
202
|
+
z-index: 1;
|
|
160
203
|
top: var(--gap);
|
|
161
204
|
left: var(--gap);
|
|
162
205
|
right: var(--gap);
|
|
@@ -165,6 +208,7 @@ function onInput() {
|
|
|
165
208
|
background-color: var(--currentColor);
|
|
166
209
|
border-radius: calc(var(--border-radius-input) * 0.5);
|
|
167
210
|
opacity: var(--opacity, 1);
|
|
211
|
+
pointer-events: none;
|
|
168
212
|
}
|
|
169
213
|
|
|
170
214
|
.mirror:hover {
|
|
@@ -6,6 +6,8 @@ import FieldInputRow from "./FieldInputRow.svelte";
|
|
|
6
6
|
import TextInput from "./TextInput.svelte";
|
|
7
7
|
|
|
8
8
|
export let value;
|
|
9
|
+
export let context = null;
|
|
10
|
+
export let key = "";
|
|
9
11
|
|
|
10
12
|
let img, input, name;
|
|
11
13
|
$: url = typeof value === HTMLImageElement ? value.src : value;
|
|
@@ -5,6 +5,8 @@ import { createEventDispatcher } from "svelte";
|
|
|
5
5
|
export let label = null;
|
|
6
6
|
export let value;
|
|
7
7
|
export let disabled = false;
|
|
8
|
+
export let context = null;
|
|
9
|
+
export let key = "";
|
|
8
10
|
|
|
9
11
|
let node;
|
|
10
12
|
|
|
@@ -16,6 +18,10 @@ function onKeyPress(event) {
|
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
function handleInput(event) {
|
|
22
|
+
dispatch('input', event.currentTarget.value);
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
function handleChange(event) {
|
|
20
26
|
dispatch('change', event.currentTarget.value);
|
|
21
27
|
}
|
|
@@ -31,7 +37,7 @@ function handleChange(event) {
|
|
|
31
37
|
bind:this={node}
|
|
32
38
|
bind:value={value}
|
|
33
39
|
on:change={handleChange}
|
|
34
|
-
on:input
|
|
40
|
+
on:input={handleInput}
|
|
35
41
|
on:keypress={onKeyPress}
|
|
36
42
|
on:keydown
|
|
37
43
|
on:focus
|