@rogieking/figui3 1.0.13 → 1.0.15

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 (4) hide show
  1. package/example.html +159 -0
  2. package/fig.css +55 -19
  3. package/fig.js +24 -13
  4. package/package.json +1 -1
package/example.html ADDED
@@ -0,0 +1,159 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport"
7
+ content="width=device-width, initial-scale=1.0">
8
+ <title>Figma UI3 Web Components</title>
9
+ <link rel="stylesheet"
10
+ type="text/css"
11
+ href="fig.css">
12
+ <script src="fig.js"></script>
13
+ </head>
14
+
15
+ <body>
16
+ <fig-header>
17
+ <h3>UI3 Components</h3>
18
+ </fig-header>
19
+ <fig-content>
20
+ <fig-tabs>
21
+ <fig-tab selected>Tab #1</fig-tab>
22
+ <fig-tab>Tab #2</fig-tab>
23
+ </fig-tabs>
24
+ <br /><br />
25
+ <fig-segmented-control>
26
+ <fig-segment selected>One</fig-segment>
27
+ <fig-segment>Two</fig-segment>
28
+ <fig-segment>Three</fig-segment>
29
+ </fig-segmented-control>
30
+ <br /><br />
31
+ <hstack>
32
+ <fig-button>Primary</fig-button>
33
+ <fig-button variant="secondary">Secondary</fig-button>
34
+ <fig-button variant="ghost">Ghost</fig-button>
35
+ <fig-button variant="ghost"
36
+ icon="true">
37
+ <svg class="svg"
38
+ xmlns="http://www.w3.org/2000/svg"
39
+ width="16"
40
+ height="16"
41
+ viewBox="0 0 16 16">
42
+ <path fill="currentColor"
43
+ fill-opacity="1"
44
+ fill-rule="evenodd"
45
+ stroke="none"
46
+ d="M8 3h2c1.933 0 3.5 1.567 3.5 3.5 0 1.933-1.567 3.5-3.5 3.5H4.707l2.147 2.146-.708.708-3-3-.353-.354.353-.354 3-3 .708.708L4.707 9H10c1.38 0 2.5-1.12 2.5-2.5C12.5 5.12 11.38 4 10 4H8z">
47
+ </path>
48
+ </svg>
49
+ </fig-button>
50
+ <fig-tooltip text="Toggle off/on">
51
+ <fig-button variant="toggle"
52
+ icon="true"
53
+ selected="true">
54
+ <svg width="24"
55
+ height="24"
56
+ fill="none"
57
+ viewBox="0 0 24 24">
58
+ <path fill="currentColor"
59
+ fill-rule="evenodd"
60
+ d="M9.5 7h-2a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5m-2-1A1.5 1.5 0 0 0 6 7.5v9A1.5 1.5 0 0 0 7.5 18h2a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 9.5 6zm9 1h-2a.5.5 0 0 0-.5.5v2a.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-.5-.5m-2-1A1.5 1.5 0 0 0 13 7.5v2a1.5 1.5 0 0 0 1.5 1.5h2A1.5 1.5 0 0 0 18 9.5v-2A1.5 1.5 0 0 0 16.5 6zm3.384 8.32a.5.5 0 0 0-.768-.64l-2.15 2.58-1.112-1.114a.5.5 0 0 0-.708.708l1.5 1.5a.5.5 0 0 0 .738-.034z"
61
+ clip-rule="evenodd"></path>
62
+ </svg>
63
+ </fig-button>
64
+ </fig-tooltip>
65
+ </hstack>
66
+ <br />
67
+ <fig-dropdown>
68
+ <option>One</option>
69
+ <option>Two</option>
70
+ </fig-dropdown>
71
+ <br />
72
+ <fig-tooltip text="Tooltip text">
73
+ <p>Tooltip</p>
74
+ </fig-tooltip>
75
+ <br /><br />
76
+ <hstack>
77
+ <input type="radio"
78
+ name="radio"
79
+ checked />
80
+ <input type="radio"
81
+ name="radio" />
82
+ </hstack>
83
+ <br /><br />
84
+ <fig-checkbox label="Checkbox"></fig-checkbox>
85
+ <br /><br />
86
+ <fig-radio label="Radio #1"
87
+ name="r1"></fig-radio>
88
+ <br /> <br />
89
+ <fig-radio label="Radio #2"
90
+ name="r1"></fig-radio>
91
+ <br /><br />
92
+ <vstack>
93
+ <fig-switch on="true"></fig-switch>
94
+ <fig-switch indeterminate="true"></fig-switch>
95
+ <fig-switch disabled></fig-switch>
96
+ </vstack>
97
+ <br /><br />
98
+ <fig-input-color value="#00FFFF33"
99
+ text="true"></fig-input-color>
100
+ <br /><br />
101
+ <fig-input-color value="#00FF00"
102
+ alpha="true"
103
+ text="true"></fig-input-color>
104
+ <br /><br />
105
+ <fig-input-text multiline="true"
106
+ value=""
107
+ autoresize="true"
108
+ resizable="true"
109
+ placeholder="Anthropic API key">
110
+ </fig-input-text>
111
+ <br />
112
+ <fig-input-text type="number"
113
+ value="10"></fig-input-text>
114
+ <br /><br />
115
+ <fig-field direction="horizontal">
116
+ <label>Field label</label>
117
+ <fig-input-text value=""
118
+ placeholder="Field placeholder"></fig-input-text>
119
+ </fig-field>
120
+ <fig-field>
121
+ <label>Label</label>
122
+ <fig-input-text value=""
123
+ placeholder="Field placeholder"></fig-input-text>
124
+ </fig-field>
125
+ <fig-slider></fig-slider>
126
+ <br />
127
+ <fig-slider text="true"
128
+ value="50"></fig-slider>
129
+ <br />
130
+ <fig-slider type="opacity"
131
+ value="0.75"
132
+ color="#ff0000"></fig-slider>
133
+ <br />
134
+ <fig-slider type="hue"
135
+ value="55"></fig-slider>
136
+ <br />
137
+ <fig-slider value="50"
138
+ step="25">
139
+ <datalist id="markers">
140
+ <option value="0"></option>
141
+ <option value="25"></option>
142
+ <option value="50"></option>
143
+ <option value="75"></option>
144
+ <option value="100"></option>
145
+ </datalist>
146
+ </fig-slider>
147
+ <br />
148
+ <fig-slider type="delta"
149
+ value="2"
150
+ default="0"
151
+ max="5"
152
+ min="-5"></fig-slider>
153
+ <br />
154
+ <fig-spinner></fig-spinner>
155
+ </fig-content>
156
+
157
+ </body>
158
+
159
+ </html>
package/fig.css CHANGED
@@ -361,7 +361,7 @@
361
361
  --bg-selected-active: #E5F4FF;
362
362
  --bg-tooltip: #1E1E1E;
363
363
  --body-medium-fontSize: 0.6875rem;
364
- --border-selected: #0D99FF;
364
+ --figma-color-border-selected: #0D99FF;
365
365
  --spacer-1: .25rem;
366
366
  --spacer-2: .5rem;
367
367
  --spacer-3: 1rem;
@@ -498,7 +498,7 @@ input[type=number],
498
498
  color: inherit;
499
499
 
500
500
  &:focus {
501
- box-shadow: inset 0 0 0 1px var(--border-selected);
501
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
502
502
  outline: 0;
503
503
  }
504
504
 
@@ -563,7 +563,7 @@ input[type=text][list] {
563
563
  accent-color: var(--figma-color-bg-brand);
564
564
 
565
565
  &:focus {
566
- box-shadow: inset 0 0 0 1px var(--border-selected);
566
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
567
567
  outline: 0;
568
568
  }
569
569
 
@@ -636,13 +636,6 @@ input[type=button] {
636
636
  outline: 0;
637
637
  background-color: var(--figma-color-bg-selected);
638
638
  }
639
-
640
- &:focus {
641
- outline: 0;
642
- background-color: transparent;
643
- box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
644
- }
645
-
646
639
  }
647
640
 
648
641
  &[variant="ghost"][disabled=true],
@@ -731,6 +724,11 @@ input[type=button] {
731
724
  color: var(--figma-color-icon-brand);
732
725
  background-color: var(--figma-color-bg-selected);
733
726
  }
727
+
728
+ &:focus {
729
+ outline: 0;
730
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
731
+ }
734
732
  }
735
733
 
736
734
  fig-button>button {
@@ -848,7 +846,7 @@ input[type=color] {
848
846
  background-color: var(--figma-color-bg-secondary);
849
847
 
850
848
  &:focus {
851
- box-shadow: inset 0 0 0 1px var(--border-selected);
849
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
852
850
  outline: 0;
853
851
  }
854
852
  }
@@ -987,6 +985,11 @@ input[type=checkbox]:not(.switch) {
987
985
  background-color: var(--figma-color-bg-brand);
988
986
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.50012 7.5L7.50012 10.5L11.5001 4.5' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.125' /%3E%3C/svg%3E%0A");
989
987
  }
988
+
989
+ &:focus {
990
+ outline: 0;
991
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
992
+ }
990
993
  }
991
994
 
992
995
  .figma-light input[type=checkbox]:not(.switch):hover {
@@ -1023,8 +1026,15 @@ input[type=radio] {
1023
1026
  }
1024
1027
 
1025
1028
  &:focus {
1026
- box-shadow: inset 0 0 0 1px var(--border-selected);
1027
1029
  outline: 0;
1030
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
1031
+ }
1032
+
1033
+ &:hover:not(:checked) {
1034
+ &::after {
1035
+ transform: scale(1);
1036
+ opacity: 0.25;
1037
+ }
1028
1038
  }
1029
1039
 
1030
1040
  &::after {
@@ -1034,7 +1044,6 @@ input[type=radio] {
1034
1044
  border-radius: 0.25rem;
1035
1045
  background-color: var(--figma-color-text-onbrand);
1036
1046
  transform: scale(0);
1037
- transition: var(--input-transition);
1038
1047
  box-shadow:
1039
1048
  0px 0 0 0.75px rgba(0, 0, 0, 0.1),
1040
1049
  0px 1px 3px 0px rgba(0, 0, 0, 0.1),
@@ -1168,6 +1177,8 @@ details {
1168
1177
  fig-slider {
1169
1178
  --slider-height: 1rem;
1170
1179
  --slider-percent: calc(var(--slider-complete) * 100%);
1180
+ --start-percent: calc(var(--default, 0) * 100%);
1181
+ --slider-tick-size: calc(var(--slider-height)/4);
1171
1182
  --slider-handle-shadow: inset 0 0 0 4px var(--figma-color-icon-onbrand),
1172
1183
  inset 0 0 0 5px rgba(0, 0, 0, 0.1),
1173
1184
  0px 0 0 0.75px rgba(0, 0, 0, 0.1),
@@ -1180,7 +1191,7 @@ fig-slider {
1180
1191
  0px 1px 3px 0px rgba(0, 0, 0, 0.1),
1181
1192
  0px 3px 8px 0px rgba(0, 0, 0, 0.1),
1182
1193
  0px 0px 0.5px 0px rgba(0, 0, 0, 0.18),
1183
- 0 0 0 1px var(--border-selected);
1194
+ 0 0 0 1px var(--figma-color-border-selected);
1184
1195
 
1185
1196
  display: inline-flex;
1186
1197
  align-items: center;
@@ -1207,6 +1218,32 @@ fig-slider {
1207
1218
  }
1208
1219
  }
1209
1220
 
1221
+ /* TODO: Delta sizing */
1222
+ &[type=delta] {
1223
+ .fig-slider-input-container {
1224
+ &::before {
1225
+ --left-start: calc(var(--start-percent) - var(--slider-height)/2);
1226
+ left: min(var(--left-start), var(--slider-percent));
1227
+ --width: calc(var(--slider-percent) - var(--start-percent));
1228
+ --abs-width: max(var(--width) + var(--slider-height)/2, -1*var(--width) + var(--slider-height)/2);
1229
+ width: var(--abs-width);
1230
+ }
1231
+
1232
+ &::after {
1233
+ content: '';
1234
+ width: var(--slider-tick-size);
1235
+ height: var(--slider-tick-size);
1236
+ aspect-ratio: 1;
1237
+ border-radius: 100%;
1238
+ font-size: 0;
1239
+ position: absolute;
1240
+ left: calc(var(--start-percent) - var(--slider-tick-size)/2);
1241
+ top: calc(50% - var(--slider-tick-size)/2);
1242
+ background: var(--figma-color-icon-tertiary);
1243
+ }
1244
+ }
1245
+ }
1246
+
1210
1247
  &[type=hue],
1211
1248
  &[type=opacity] {
1212
1249
  .fig-slider-input-container {
@@ -1342,7 +1379,6 @@ fig-slider {
1342
1379
  }
1343
1380
 
1344
1381
  datalist {
1345
- --dot-size: calc(var(--slider-height)/4);
1346
1382
  position: absolute;
1347
1383
  inset: 0;
1348
1384
  display: flex;
@@ -1351,7 +1387,7 @@ fig-slider {
1351
1387
  margin: 0;
1352
1388
  border: 0;
1353
1389
  appearance: none;
1354
- padding: 0 calc((var(--slider-height)/2) - var(--dot-size)/2);
1390
+ padding: 0 calc((var(--slider-height)/2) - var(--slider-tick-size)/2);
1355
1391
  height: var(--slider-height);
1356
1392
  pointer-events: none;
1357
1393
  justify-content: space-between;
@@ -1359,8 +1395,8 @@ fig-slider {
1359
1395
 
1360
1396
  & option {
1361
1397
  appearance: none;
1362
- width: var(--dot-size);
1363
- height: var(--dot-size);
1398
+ width: var(--slider-tick-size);
1399
+ height: var(--slider-tick-size);
1364
1400
  aspect-ratio: 1;
1365
1401
  margin: 0;
1366
1402
  padding: 0;
@@ -1680,7 +1716,7 @@ fig-input-text {
1680
1716
  }
1681
1717
 
1682
1718
  &:has(input:focus) {
1683
- box-shadow: inset 0 0 0 1px var(--border-selected);
1719
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
1684
1720
  outline: 0;
1685
1721
  }
1686
1722
  }
package/fig.js CHANGED
@@ -25,6 +25,7 @@ class FigButton extends HTMLElement {
25
25
  border: 0;
26
26
  font: inherit;
27
27
  color: inherit;
28
+ outline: 0;
28
29
  background: transparent;
29
30
  }
30
31
  </style>
@@ -490,6 +491,7 @@ class FigSlider extends HTMLElement {
490
491
  #typeDefaults = {
491
492
  range: { min: 0, max: 100, step: 1 },
492
493
  hue: { min: 0, max: 255, step: 1 },
494
+ delta: { min: -100, max: 100, step: 1 },
493
495
  opacity: { min: 0, max: 1, step: 0.01, color: "#FF0000" }
494
496
  }
495
497
  constructor() {
@@ -498,6 +500,7 @@ class FigSlider extends HTMLElement {
498
500
  connectedCallback() {
499
501
 
500
502
  this.value = this.getAttribute("value")
503
+ this.default = this.getAttribute("default") || null
501
504
  this.type = this.getAttribute("type") || "range"
502
505
 
503
506
  const defaults = this.#typeDefaults[this.type]
@@ -554,6 +557,10 @@ class FigSlider extends HTMLElement {
554
557
  if (this.textInput) {
555
558
  this.textInput.addEventListener("input", this.handleTextInput.bind(this))
556
559
  }
560
+
561
+ if (this.default) {
562
+ this.style.setProperty("--default", this.calculateNormal(this.default))
563
+ }
557
564
  }
558
565
  static get observedAttributes() {
559
566
  return ['value', 'step', 'min', 'max', 'type', 'disabled']
@@ -596,13 +603,17 @@ class FigSlider extends HTMLElement {
596
603
  this.handleInput()
597
604
  }
598
605
  }
599
-
600
- handleInput() {
606
+ calculateNormal(value) {
601
607
  let min = Number(this.input.min)
602
608
  let max = Number(this.input.max)
609
+ let val = Number(value)
610
+ return (val - min) / (max - min)
611
+ }
612
+
613
+ handleInput() {
603
614
  let val = Number(this.input.value)
604
615
  this.value = val
605
- let complete = (val - min) / (max - min)
616
+ let complete = this.calculateNormal(val)
606
617
  this.style.setProperty("--slider-complete", complete)
607
618
  if (this.textInput) {
608
619
  this.textInput.value = val
@@ -678,18 +689,18 @@ class FigField extends HTMLElement {
678
689
  super()
679
690
  }
680
691
  connectedCallback() {
681
- this.label = this.querySelector('label')
682
- this.input = Array.from(this.childNodes).find(node => node.nodeName.toLowerCase().startsWith("fig-"))
683
- console.log('input:', this.input)
684
- if (this.input) {
685
- this.label.addEventListener('click', this.focus.bind(this))
686
- }
692
+ requestAnimationFrame(() => {
693
+ this.label = this.querySelector('label')
694
+ this.input = Array.from(this.childNodes).find(node => node.nodeName.toLowerCase().startsWith("fig-"))
695
+ if (this.input && this.label) {
696
+ this.label.addEventListener('click', this.focus.bind(this))
697
+ let inputId = this.input.getAttribute("id") || uniqueId()
698
+ this.input.setAttribute("id", inputId)
699
+ this.label.setAttribute("for", inputId)
700
+ }
701
+ })
687
702
  }
688
703
  focus() {
689
- if (!this.input) {
690
- this.input = Array.from(this.childNodes).find(node => node.nodeName.toLowerCase().startsWith("fig-"))
691
- }
692
- console.log('input:', this.input)
693
704
  this.input.focus()
694
705
  }
695
706
  }
package/package.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "1.0.13"
3
+ "version": "1.0.15"
4
4
  }