@xsynaptic/sonic-ui 0.1.0

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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/define/dial.d.ts +2 -0
  4. package/dist/define/dial.js +8 -0
  5. package/dist/define/dial.js.map +1 -0
  6. package/dist/define/key.d.ts +2 -0
  7. package/dist/define/key.js +8 -0
  8. package/dist/define/key.js.map +1 -0
  9. package/dist/define/meter.d.ts +2 -0
  10. package/dist/define/meter.js +8 -0
  11. package/dist/define/meter.js.map +1 -0
  12. package/dist/define/segmented.d.ts +2 -0
  13. package/dist/define/segmented.js +8 -0
  14. package/dist/define/segmented.js.map +1 -0
  15. package/dist/define/slider.d.ts +2 -0
  16. package/dist/define/slider.js +8 -0
  17. package/dist/define/slider.js.map +1 -0
  18. package/dist/define.d.ts +11 -0
  19. package/dist/define.js +5 -0
  20. package/dist/elements/define-once.js +8 -0
  21. package/dist/elements/define-once.js.map +1 -0
  22. package/dist/elements/dial.d.ts +15 -0
  23. package/dist/elements/dial.js +57 -0
  24. package/dist/elements/dial.js.map +1 -0
  25. package/dist/elements/key.d.ts +17 -0
  26. package/dist/elements/key.js +99 -0
  27. package/dist/elements/key.js.map +1 -0
  28. package/dist/elements/meter.d.ts +17 -0
  29. package/dist/elements/meter.js +119 -0
  30. package/dist/elements/meter.js.map +1 -0
  31. package/dist/elements/range-element.d.ts +32 -0
  32. package/dist/elements/range-element.js +348 -0
  33. package/dist/elements/range-element.js.map +1 -0
  34. package/dist/elements/range-entry.js +73 -0
  35. package/dist/elements/range-entry.js.map +1 -0
  36. package/dist/elements/segmented.d.ts +17 -0
  37. package/dist/elements/segmented.js +104 -0
  38. package/dist/elements/segmented.js.map +1 -0
  39. package/dist/elements/slider.d.ts +15 -0
  40. package/dist/elements/slider.js +70 -0
  41. package/dist/elements/slider.js.map +1 -0
  42. package/dist/elements/sonic-element.d.ts +20 -0
  43. package/dist/elements/sonic-element.js +94 -0
  44. package/dist/elements/sonic-element.js.map +1 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.js +7 -0
  47. package/dist/lib/read-px-property.js +9 -0
  48. package/dist/lib/read-px-property.js.map +1 -0
  49. package/dist/lib/render.js +19 -0
  50. package/dist/lib/render.js.map +1 -0
  51. package/dist/lib/taper.js +33 -0
  52. package/dist/lib/taper.js.map +1 -0
  53. package/dist/lib/write-attribute.js +12 -0
  54. package/dist/lib/write-attribute.js.map +1 -0
  55. package/dist/skins/ivory.css +8 -0
  56. package/dist/skins/lime.css +10 -0
  57. package/dist/skins/slate.css +10 -0
  58. package/dist/styles/controls.css +8 -0
  59. package/dist/styles/dial.css +265 -0
  60. package/dist/styles/key.css +137 -0
  61. package/dist/styles/material.css +229 -0
  62. package/dist/styles/meter.css +271 -0
  63. package/dist/styles/screen.css +47 -0
  64. package/dist/styles/segmented.css +147 -0
  65. package/dist/styles/slider.css +204 -0
  66. package/package.json +76 -0
@@ -0,0 +1,147 @@
1
+ @layer sonic {
2
+ /* On the host too, for the placeholder */
3
+ :is(sonic-segmented, .sonic-segmented) {
4
+ --_sonic-segmented-size: var(--sonic-segmented-size, 2rem);
5
+ }
6
+
7
+ :has(> .sonic-segmented):not([hidden]) {
8
+ display: contents;
9
+ }
10
+
11
+ /* Hides the options, which have no size before upgrade */
12
+ sonic-segmented:not(:defined, [hidden]) {
13
+ display: block;
14
+ visibility: hidden;
15
+ flex-shrink: 0;
16
+ inline-size: var(--_sonic-segmented-size);
17
+ block-size: var(--_sonic-segmented-size);
18
+ overflow: hidden;
19
+ }
20
+
21
+ .sonic-segmented {
22
+ --_sonic-segmented-gap-ratio: var(--sonic-segmented-gap-ratio, 0.06);
23
+ --_sonic-segmented-radius-ratio: var(--sonic-segmented-radius-ratio, 0.2);
24
+ --_sonic-segmented-bevel-ratio: var(--sonic-segmented-bevel-ratio, 0.075);
25
+ --_sonic-segmented-depth-ratio: var(--sonic-segmented-depth-ratio, 0.03);
26
+ --_sonic-segmented-press-scale: var(--sonic-segmented-press-scale, 0.985);
27
+ --_sonic-segmented-font-ratio: var(--sonic-segmented-font-ratio, 0.34);
28
+ --_sonic-segmented-icon-ratio: var(--sonic-segmented-icon-ratio, 0.5);
29
+ --_sonic-unit: calc(var(--_sonic-segmented-size) / 32);
30
+ --_sonic-segmented-corner: calc(
31
+ var(--_sonic-segmented-size) * var(--_sonic-segmented-radius-ratio)
32
+ );
33
+ --_sonic-segmented-depth: calc(
34
+ var(--_sonic-segmented-size) * var(--_sonic-segmented-depth-ratio)
35
+ );
36
+ --_sonic-segmented-gap: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-gap-ratio));
37
+
38
+ /* Concentric with the well's corner */
39
+ --_sonic-segmented-inner-corner: max(
40
+ 0px,
41
+ var(--_sonic-segmented-corner) - var(--_sonic-segmented-gap)
42
+ );
43
+
44
+ box-sizing: border-box;
45
+ display: flex;
46
+ flex-shrink: 0;
47
+ gap: var(--_sonic-segmented-gap);
48
+ block-size: var(--_sonic-segmented-size);
49
+ padding: var(--_sonic-segmented-gap);
50
+ user-select: none;
51
+ background: linear-gradient(
52
+ var(--_sonic-light-fall),
53
+ color-mix(in oklab, var(--_sonic-unlit) 55%, #000),
54
+ color-mix(in oklab, var(--_sonic-unlit) 85%, #000)
55
+ );
56
+ border-radius: var(--_sonic-segmented-corner);
57
+ box-shadow: var(--_sonic-well);
58
+ }
59
+
60
+ .sonic-segmented-segment {
61
+ --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / -2);
62
+ --_sonic-segmented-scale: 1;
63
+ --_sonic-segmented-drop: calc(1.5 * var(--_sonic-cast-x)) calc(1.5 * var(--_sonic-cast-y))
64
+ calc(2 * var(--_sonic-unit)) rgb(0 0 0 / 65%);
65
+ --_sonic-segmented-glow: transparent;
66
+
67
+ display: grid;
68
+ min-inline-size: calc(var(--_sonic-segmented-size) - 2 * var(--_sonic-segmented-gap));
69
+ padding: 0;
70
+ font: inherit;
71
+ font-size: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-font-ratio));
72
+ line-height: 1;
73
+ color: var(--_sonic-ink);
74
+ cursor: pointer;
75
+ background: transparent;
76
+ border: 0;
77
+ border-radius: var(--_sonic-segmented-inner-corner);
78
+ }
79
+
80
+ .sonic-segmented-segment:active:where(:not(:disabled)),
81
+ .sonic-segmented-segment[aria-checked='true'] {
82
+ --_sonic-segmented-shift: calc(var(--_sonic-segmented-depth) / 2);
83
+ --_sonic-segmented-scale: var(--_sonic-segmented-press-scale);
84
+ --_sonic-segmented-drop: calc(0.5 * var(--_sonic-cast-x)) calc(0.5 * var(--_sonic-cast-y))
85
+ var(--_sonic-unit) rgb(0 0 0 / 65%);
86
+ }
87
+
88
+ .sonic-segmented-segment[aria-checked='true'] {
89
+ --_sonic-segmented-glow: color-mix(in oklab, var(--_sonic-lit) 22%, transparent);
90
+
91
+ color: var(--_sonic-lit);
92
+ background: var(--_sonic-lit);
93
+ box-shadow: var(--_sonic-well);
94
+ }
95
+
96
+ .sonic-segmented-segment:disabled {
97
+ --_sonic-lit: var(--_sonic-lit-disabled);
98
+
99
+ color: var(--_sonic-etch);
100
+ cursor: default;
101
+ }
102
+
103
+ /* In flow, so a long label widens its segment rather than spilling over the next */
104
+ .sonic-segmented-cap {
105
+ position: relative;
106
+ display: grid;
107
+ place-items: center;
108
+ padding-inline: calc(var(--_sonic-segmented-size) * 0.25);
109
+ background: var(--_sonic-skirt);
110
+ border-radius: var(--_sonic-segmented-inner-corner);
111
+ box-shadow: var(--_sonic-segmented-drop), var(--_sonic-rim), var(--_sonic-focus-shadow);
112
+ scale: var(--_sonic-segmented-scale);
113
+ translate: 0 var(--_sonic-segmented-shift);
114
+ transition: var(--_sonic-press-transition);
115
+
116
+ &::before {
117
+ position: absolute;
118
+ inset: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-bevel-ratio));
119
+ content: '';
120
+ background:
121
+ radial-gradient(closest-side, var(--_sonic-segmented-glow), transparent),
122
+ var(--_sonic-sheen), var(--_sonic-face);
123
+ border-radius: max(
124
+ 0px,
125
+ var(--_sonic-segmented-inner-corner) - var(--_sonic-segmented-size) *
126
+ var(--_sonic-segmented-bevel-ratio)
127
+ );
128
+ box-shadow: var(--_sonic-face-shadow);
129
+ }
130
+
131
+ & > * {
132
+ position: relative;
133
+ filter: var(--_sonic-engraving);
134
+ }
135
+
136
+ & > svg {
137
+ inline-size: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-icon-ratio));
138
+ block-size: calc(var(--_sonic-segmented-size) * var(--_sonic-segmented-icon-ratio));
139
+ }
140
+ }
141
+
142
+ /* Engraving under the glow keeps a lit label's edge */
143
+ .sonic-segmented-segment[aria-checked='true'] .sonic-segmented-cap > * {
144
+ filter: var(--_sonic-engraving)
145
+ drop-shadow(0 0 var(--_sonic-unit) color-mix(in oklab, var(--_sonic-lit) 35%, transparent));
146
+ }
147
+ }
@@ -0,0 +1,204 @@
1
+ /* The size is the thickness across the travel */
2
+ @layer sonic {
3
+ /* On the host too, for the placeholder */
4
+ :is(sonic-slider, .sonic-slider) {
5
+ --_sonic-slider-size: var(--sonic-slider-size, 2rem);
6
+ --_sonic-slider-length: var(--sonic-slider-length, 8rem);
7
+ }
8
+
9
+ :has(> .sonic-slider):not([hidden]) {
10
+ display: contents;
11
+ }
12
+
13
+ sonic-slider:not(:defined, [hidden]) {
14
+ display: block;
15
+ flex-shrink: 0;
16
+ inline-size: var(--_sonic-slider-length);
17
+ block-size: var(--_sonic-slider-size);
18
+ }
19
+
20
+ sonic-slider[orientation='vertical']:not(:defined, [hidden]) {
21
+ inline-size: var(--_sonic-slider-size);
22
+ block-size: var(--_sonic-slider-length);
23
+ }
24
+
25
+ /* Laid out on its side rather than rotated, so the light falls the same way in both orientations */
26
+ .sonic-slider {
27
+ --_sonic-slider-groove-ratio: var(--sonic-slider-groove-ratio, 0.15);
28
+
29
+ /* Along the travel; across it, the cap fills the size */
30
+ --_sonic-slider-cap-ratio: var(--sonic-slider-cap-ratio, 0.5);
31
+ --_sonic-slider-radius-ratio: var(--sonic-slider-radius-ratio, 0.15);
32
+ --_sonic-slider-bevel-ratio: var(--sonic-slider-bevel-ratio, 0.075);
33
+ --_sonic-slider-pointer-ratio: var(--sonic-slider-pointer-ratio, 0.07);
34
+ --_sonic-unit: calc(var(--_sonic-slider-size) / 32);
35
+ --_sonic-slider-lit: var(--_sonic-lit);
36
+ --_sonic-slider-toward: to right;
37
+ --_sonic-slider-across: to bottom;
38
+ --_sonic-slider-cursor: ew-resize;
39
+ --_sonic-slider-groove: calc(var(--_sonic-slider-size) * var(--_sonic-slider-groove-ratio));
40
+ --_sonic-slider-cap: calc(var(--_sonic-slider-size) * var(--_sonic-slider-cap-ratio));
41
+ --_sonic-slider-travel: calc(var(--_sonic-slider-length) - var(--_sonic-slider-cap));
42
+ --_sonic-slider-offset: calc(var(--_sonic-slider-value, 0) * var(--_sonic-slider-travel));
43
+
44
+ position: relative;
45
+ flex-shrink: 0;
46
+ inline-size: var(--_sonic-slider-length);
47
+ block-size: var(--_sonic-slider-size);
48
+ touch-action: none;
49
+ cursor: var(--_sonic-slider-cursor);
50
+ user-select: none;
51
+ }
52
+
53
+ [orientation='vertical'] > .sonic-slider {
54
+ --_sonic-slider-toward: to top;
55
+ --_sonic-slider-across: to right;
56
+ --_sonic-slider-cursor: ns-resize;
57
+
58
+ inline-size: var(--_sonic-slider-size);
59
+ block-size: var(--_sonic-slider-length);
60
+ }
61
+
62
+ :state(dragging) > .sonic-slider {
63
+ --_sonic-cap: var(--_sonic-cap-hover);
64
+ }
65
+
66
+ [dimmed] > .sonic-slider {
67
+ --_sonic-slider-lit: var(--_sonic-lit-off);
68
+ }
69
+
70
+ [disabled] > .sonic-slider {
71
+ --_sonic-slider-lit: var(--_sonic-lit-disabled);
72
+ --_sonic-slider-cursor: default;
73
+ }
74
+
75
+ [groove-press='none']:not(:state(dragging)) > .sonic-slider {
76
+ cursor: default;
77
+ }
78
+
79
+ .sonic-slider-marks {
80
+ --_sonic-slider-mark-pitch: calc(
81
+ var(--_sonic-slider-travel) / (var(--_sonic-slider-positions, 2) - 1)
82
+ );
83
+ --_sonic-slider-mark-lip: calc(
84
+ var(--_sonic-slider-groove) / 2 + var(--_sonic-slider-size) * 0.1
85
+ );
86
+
87
+ position: absolute;
88
+ inset: 0 calc((var(--_sonic-slider-cap) - var(--_sonic-unit)) / 2);
89
+ background: repeating-linear-gradient(
90
+ var(--_sonic-slider-toward),
91
+ var(--_sonic-etch) 0 var(--_sonic-unit),
92
+ transparent 0 var(--_sonic-slider-mark-pitch)
93
+ );
94
+ mask: linear-gradient(
95
+ var(--_sonic-slider-across),
96
+ transparent 15%,
97
+ #000 0 calc(50% - var(--_sonic-slider-mark-lip)),
98
+ transparent 0 calc(50% + var(--_sonic-slider-mark-lip)),
99
+ #000 0 85%,
100
+ transparent 0
101
+ );
102
+ }
103
+
104
+ [orientation='vertical'] > .sonic-slider > .sonic-slider-marks {
105
+ inset: calc((var(--_sonic-slider-cap) - var(--_sonic-unit)) / 2) 0;
106
+ }
107
+
108
+ :not([notched]) > .sonic-slider > .sonic-slider-marks {
109
+ display: none;
110
+ }
111
+
112
+ .sonic-slider-groove {
113
+ --_sonic-slider-lit-low: min(var(--_sonic-slider-origin, 0), var(--_sonic-slider-value, 0));
114
+ --_sonic-slider-lit-high: max(var(--_sonic-slider-origin, 0), var(--_sonic-slider-value, 0));
115
+
116
+ position: absolute;
117
+ inset: calc(50% - var(--_sonic-slider-groove) / 2)
118
+ calc((var(--_sonic-slider-cap) - var(--_sonic-slider-groove)) / 2);
119
+
120
+ /* At either end of the travel the light runs on to the groove's rounded end */
121
+ background: linear-gradient(
122
+ var(--_sonic-slider-toward),
123
+ var(--_sonic-unlit)
124
+ calc(
125
+ var(--_sonic-slider-lit-low) * var(--_sonic-slider-travel) + var(--_sonic-slider-groove) /
126
+ 2 * sign(var(--_sonic-slider-lit-low))
127
+ ),
128
+ var(--_sonic-slider-lit) 0
129
+ calc(
130
+ var(--_sonic-slider-lit-high) * var(--_sonic-slider-travel) +
131
+ var(--_sonic-slider-groove) / 2 * (2 - sign(1 - var(--_sonic-slider-lit-high)))
132
+ ),
133
+ var(--_sonic-unlit) 0
134
+ );
135
+ border-radius: calc(var(--_sonic-slider-groove) / 2);
136
+ box-shadow: var(--_sonic-groove);
137
+ }
138
+
139
+ [orientation='vertical'] > .sonic-slider > .sonic-slider-groove {
140
+ inset: calc((var(--_sonic-slider-cap) - var(--_sonic-slider-groove)) / 2)
141
+ calc(50% - var(--_sonic-slider-groove) / 2);
142
+ }
143
+
144
+ .sonic-slider-cap {
145
+ --_sonic-slider-pointer-width: calc(
146
+ var(--_sonic-slider-size) * var(--_sonic-slider-pointer-ratio)
147
+ );
148
+ --_sonic-slider-bevel: calc(var(--_sonic-slider-size) * var(--_sonic-slider-bevel-ratio));
149
+ --_sonic-slider-corner: calc(var(--_sonic-slider-size) * var(--_sonic-slider-radius-ratio));
150
+ --_sonic-slider-index-inset: calc(var(--_sonic-slider-bevel) + var(--_sonic-slider-size) * 0.1);
151
+
152
+ position: absolute;
153
+ inset: 0 auto 0 0;
154
+ inline-size: var(--_sonic-slider-cap);
155
+ background: var(--_sonic-skirt);
156
+ border-radius: var(--_sonic-slider-corner);
157
+ box-shadow:
158
+ calc(2 * var(--_sonic-cast-x)) calc(2 * var(--_sonic-cast-y)) calc(3 * var(--_sonic-unit))
159
+ rgb(0 0 0 / 65%),
160
+ var(--_sonic-rim),
161
+ var(--_sonic-focus-shadow);
162
+ translate: var(--_sonic-slider-offset) 0;
163
+
164
+ &::before,
165
+ &::after {
166
+ position: absolute;
167
+ content: '';
168
+ }
169
+
170
+ &::before {
171
+ inset: var(--_sonic-slider-bevel);
172
+ background: var(--_sonic-face);
173
+ border-radius: max(0px, var(--_sonic-slider-corner) - var(--_sonic-slider-bevel));
174
+ box-shadow: var(--_sonic-face-shadow);
175
+ }
176
+
177
+ /* Stops short of the face's edge, where its round ends clash with the straight bevel */
178
+ &::after {
179
+ inset: var(--_sonic-slider-index-inset) calc(50% - var(--_sonic-slider-pointer-width) / 2);
180
+ background: var(--_sonic-ink);
181
+ border-radius: calc(var(--_sonic-slider-pointer-width) / 2);
182
+ box-shadow: inset 0 0 calc(0.75 * var(--_sonic-unit)) rgb(0 0 0 / 55%);
183
+ }
184
+ }
185
+
186
+ [orientation='vertical'] > .sonic-slider > .sonic-slider-cap {
187
+ inset: auto 0 0;
188
+ inline-size: auto;
189
+ block-size: var(--_sonic-slider-cap);
190
+ translate: 0 calc(-1 * var(--_sonic-slider-offset));
191
+
192
+ &::after {
193
+ inset: calc(50% - var(--_sonic-slider-pointer-width) / 2) var(--_sonic-slider-index-inset);
194
+ }
195
+ }
196
+
197
+ [disabled] > .sonic-slider > .sonic-slider-cap::after {
198
+ background: var(--_sonic-etch);
199
+ }
200
+
201
+ [groove-press='none'] > .sonic-slider > .sonic-slider-cap {
202
+ cursor: var(--_sonic-slider-cursor);
203
+ }
204
+ }
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@xsynaptic/sonic-ui",
3
+ "version": "0.1.0",
4
+ "description": "Native custom elements for audio interfaces: dials, sliders, keys, a segmented switch, a peak meter and a screen panel, skinned with CSS custom properties",
5
+ "keywords": [
6
+ "custom-elements",
7
+ "web-components",
8
+ "audio",
9
+ "knob",
10
+ "dial",
11
+ "slider",
12
+ "fader",
13
+ "synth"
14
+ ],
15
+ "homepage": "https://github.com/xsynaptic/sonic-ui#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/xsynaptic/sonic-ui/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/xsynaptic/sonic-ui.git",
22
+ "directory": "packages/sonic-ui"
23
+ },
24
+ "license": "MIT",
25
+ "author": "Alexander Synaptic <x@synapticism.com>",
26
+ "type": "module",
27
+ "engines": {
28
+ "node": ">=24.0.0"
29
+ },
30
+ "sideEffects": [
31
+ "./dist/define.js",
32
+ "./dist/define/*.js",
33
+ "./src/define.ts",
34
+ "./src/define/*.ts",
35
+ "*.css"
36
+ ],
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js"
41
+ },
42
+ "./define": {
43
+ "types": "./dist/define.d.ts",
44
+ "import": "./dist/define.js"
45
+ },
46
+ "./define/*": {
47
+ "types": "./dist/define/*.d.ts",
48
+ "import": "./dist/define/*.js"
49
+ },
50
+ "./controls.css": "./dist/styles/controls.css",
51
+ "./material.css": "./dist/styles/material.css",
52
+ "./dial.css": "./dist/styles/dial.css",
53
+ "./key.css": "./dist/styles/key.css",
54
+ "./meter.css": "./dist/styles/meter.css",
55
+ "./screen.css": "./dist/styles/screen.css",
56
+ "./segmented.css": "./dist/styles/segmented.css",
57
+ "./slider.css": "./dist/styles/slider.css",
58
+ "./skins/*.css": "./dist/skins/*.css"
59
+ },
60
+ "imports": {
61
+ "#*": "./src/*"
62
+ },
63
+ "files": [
64
+ "dist"
65
+ ],
66
+ "devDependencies": {
67
+ "publint": "^0.3.24",
68
+ "tsdown": "^0.23.0",
69
+ "typescript": "^6.0.3"
70
+ },
71
+ "scripts": {
72
+ "build": "tsdown",
73
+ "dev": "tsdown --watch",
74
+ "check-types": "tsc --noEmit"
75
+ }
76
+ }