@rogieking/figui3 1.0.36 → 1.0.38

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 +27 -6
  2. package/fig.css +39 -9
  3. package/fig.js +192 -32
  4. package/package.json +1 -1
package/example.html CHANGED
@@ -16,6 +16,9 @@
16
16
  <fig-header>
17
17
  <h3>UI3 Components</h3>
18
18
  </fig-header>
19
+ <fig-avatar src="https://avatars.githubusercontent.com/u/12345678?v=4"
20
+ name="John Doe"></fig-avatar>
21
+ <fig-avatar name="John Doe"></fig-avatar>
19
22
  <fig-content>
20
23
  <fig-tabs>
21
24
  <fig-tab selected>Tab #1</fig-tab>
@@ -66,10 +69,18 @@
66
69
  </fig-tooltip>
67
70
  </hstack>
68
71
  <br />
69
- <fig-dropdown>
70
- <option>One</option>
71
- <option>Two</option>
72
- </fig-dropdown>
72
+ <fig-field direction="horizontal">
73
+ <label>Dropdown</label>
74
+ <fig-dropdown>
75
+ <option>One</option>
76
+ <option>Two</option>
77
+ </fig-dropdown>
78
+ </fig-field>
79
+ <br />
80
+ <fig-combo-input options="House, Apartment, Condo, Other"
81
+ placeholder="Type of residence">
82
+
83
+ </fig-combo-input>
73
84
  <br />
74
85
  <fig-tooltip text="Tooltip text">
75
86
  <p>Tooltip</p>
@@ -114,6 +125,11 @@
114
125
  <fig-input-text type="number"
115
126
  value="10"></fig-input-text>
116
127
  <br /><br />
128
+ <fig-input-text value=""
129
+ placeholder="Number">
130
+ <span slot="prepend">X</span>
131
+ </fig-input-text>
132
+ <br /><br />
117
133
  <fig-field direction="horizontal">
118
134
  <label>Field label</label>
119
135
  <fig-input-text value=""
@@ -126,12 +142,15 @@
126
142
  </fig-field>
127
143
  <fig-field>
128
144
  <label>Default slider</label>
129
- <fig-slider></fig-slider>
145
+ <fig-slider default="25"
146
+ min="0"
147
+ max="500"></fig-slider>
130
148
  </fig-field>
131
149
 
132
150
  <fig-field>
133
151
  <label>Number slider (with number input)</label>
134
152
  <fig-slider text="true"
153
+ default="50"
135
154
  value="50"></fig-slider>
136
155
  </fig-field>
137
156
 
@@ -151,7 +170,9 @@
151
170
 
152
171
  <fig-field>
153
172
  <label>Stepper slider</label>
154
- <fig-slider value="50"
173
+ <fig-slider type="stepper"
174
+ value="25"
175
+ default="50"
155
176
  step="25">
156
177
  <datalist id="markers">
157
178
  <option value="0"></option>
package/fig.css CHANGED
@@ -684,6 +684,12 @@ fig-button {
684
684
  }
685
685
  }
686
686
 
687
+ /* Variant: Input */
688
+ &[variant="input"] {
689
+ background-color: var(--figma-color-bg-secondary);
690
+ box-shadow: none;
691
+ }
692
+
687
693
  /* Icon only */
688
694
  &[icon],
689
695
  &[icon] > button {
@@ -841,7 +847,8 @@ fig-tabs,
841
847
  }
842
848
 
843
849
  /* Avatar */
844
- .avatar {
850
+ fig-avatar,
851
+ .fig-avatar {
845
852
  width: 1.5rem;
846
853
  display: inline-grid;
847
854
  place-items: center;
@@ -858,7 +865,8 @@ fig-tabs,
858
865
  }
859
866
  }
860
867
 
861
- .avatar img {
868
+ fig-avatar img,
869
+ .fig-avatar img {
862
870
  position: absolute;
863
871
  background: var(--checkerboard);
864
872
  width: 1.5rem;
@@ -867,7 +875,8 @@ fig-tabs,
867
875
  box-shadow: inset 0 0 0 1px var(--figma-color-bordertranslucent);
868
876
  }
869
877
 
870
- .avatar::after {
878
+ fig-avatar::after,
879
+ .fig-avatar::after {
871
880
  content: attr(initials);
872
881
  }
873
882
 
@@ -1098,9 +1107,9 @@ input[type="radio"] {
1098
1107
 
1099
1108
  &::after {
1100
1109
  content: "";
1101
- width: 0.5rem;
1102
- height: 0.5rem;
1103
- border-radius: 0.25rem;
1110
+ width: 0.375rem;
1111
+ height: 0.375rem;
1112
+ border-radius: 100%;
1104
1113
  background-color: var(--figma-color-text-onbrand);
1105
1114
  transform: scale(0);
1106
1115
  box-shadow: 0px 0 0 0.75px rgba(0, 0, 0, 0.1),
@@ -1274,8 +1283,26 @@ fig-slider {
1274
1283
  max-width: 100%;
1275
1284
  }
1276
1285
  }
1286
+ &[type="stepper"] {
1287
+ .fig-slider-input-container {
1288
+ &::before {
1289
+ display: none;
1290
+ }
1291
+ /* Default tick */
1292
+ &::after {
1293
+ content: "";
1294
+ display: block;
1295
+ width: var(--slider-tick-size);
1296
+ height: var(--slider-tick-size);
1297
+ border-radius: 100%;
1298
+ background: var(--figma-color-icon);
1299
+ position: absolute;
1300
+ left: calc(var(--default) * 100% - var(--slider-tick-size) / 2);
1301
+ top: calc(50% - var(--slider-tick-size) / 2);
1302
+ }
1303
+ }
1304
+ }
1277
1305
 
1278
- /* TODO: Delta sizing */
1279
1306
  &[type="delta"] {
1280
1307
  .fig-slider-input-container {
1281
1308
  &::before {
@@ -1353,6 +1380,7 @@ fig-slider {
1353
1380
  aspect-ratio: 1;
1354
1381
  border: none;
1355
1382
  position: relative;
1383
+ z-index: 1;
1356
1384
  box-shadow: var(--slider-handle-shadow);
1357
1385
  }
1358
1386
 
@@ -1420,6 +1448,7 @@ fig-slider {
1420
1448
  aspect-ratio: 1;
1421
1449
  border: none;
1422
1450
  position: relative;
1451
+ z-index: 1;
1423
1452
  box-shadow: var(--slider-handle-shadow);
1424
1453
  }
1425
1454
 
@@ -1783,18 +1812,19 @@ fig-input-text {
1783
1812
  }
1784
1813
 
1785
1814
  & [slot] {
1786
- padding: 0.25rem 0.5rem;
1787
- flex: 0;
1788
1815
  user-select: none;
1816
+ width: 1.5rem;
1789
1817
  color: var(--figma-color-text-secondary);
1790
1818
  }
1791
1819
 
1792
1820
  & [slot="prepend"] {
1793
1821
  padding-right: 0;
1822
+ margin-right: calc(var(--spacer-2) * -1);
1794
1823
  }
1795
1824
 
1796
1825
  & [slot="append"] {
1797
1826
  padding-left: 0;
1827
+ margin-left: calc(var(--spacer-2) * -1);
1798
1828
  }
1799
1829
 
1800
1830
  & input {
package/fig.js CHANGED
@@ -100,6 +100,7 @@ class FigDropdown extends HTMLElement {
100
100
  }
101
101
 
102
102
  render() {
103
+ this.type = this.getAttribute("type") || "select";
103
104
  this.select = document.createElement("select");
104
105
  this.optionsSlot = document.createElement("slot");
105
106
 
@@ -108,16 +109,32 @@ class FigDropdown extends HTMLElement {
108
109
 
109
110
  // Move slotted options into the select element
110
111
  this.optionsSlot.addEventListener("slotchange", this.slotChange.bind(this));
112
+
113
+ this.select.addEventListener("change", this.handleChange.bind(this));
111
114
  }
112
115
  slotChange() {
113
116
  while (this.select.firstChild) {
114
117
  this.select.firstChild.remove();
115
118
  }
119
+ if (this.type === "dropdown") {
120
+ const hiddenOption = document.createElement("option");
121
+ hiddenOption.setAttribute("hidden", "true");
122
+ hiddenOption.setAttribute("selected", "true");
123
+ this.select.appendChild(hiddenOption);
124
+ }
116
125
  this.optionsSlot.assignedNodes().forEach((node) => {
117
126
  if (node.nodeName === "OPTION") {
118
127
  this.select.appendChild(node.cloneNode(true));
119
128
  }
120
129
  });
130
+ if (this.type === "dropdown") {
131
+ this.select.selectedIndex = -1;
132
+ }
133
+ }
134
+ handleChange() {
135
+ if (this.type === "dropdown") {
136
+ this.select.selectedIndex = -1;
137
+ }
121
138
  }
122
139
  }
123
140
 
@@ -318,7 +335,6 @@ class FigDialog extends HTMLElement {
318
335
 
319
336
  /* Public methods */
320
337
  show() {
321
- console.log("show dialog", this.dialog, this.dialog?.show);
322
338
  this.dialog.show();
323
339
  }
324
340
  close() {
@@ -554,6 +570,7 @@ class FigSlider extends HTMLElement {
554
570
  range: { min: 0, max: 100, step: 1 },
555
571
  hue: { min: 0, max: 255, step: 1 },
556
572
  delta: { min: -100, max: 100, step: 1 },
573
+ stepper: { min: 0, max: 100, step: 25 },
557
574
  opacity: { min: 0, max: 1, step: 0.01, color: "#FF0000" },
558
575
  };
559
576
  constructor() {
@@ -681,7 +698,6 @@ class FigSlider extends HTMLElement {
681
698
 
682
699
  handleInput() {
683
700
  let val = Number(this.input.value);
684
- console.log(val);
685
701
  this.value = val;
686
702
  let complete = this.calculateNormal(val);
687
703
  let defaultValue = this.calculateNormal(this.default);
@@ -700,10 +716,8 @@ class FigInputText extends HTMLElement {
700
716
  super();
701
717
  }
702
718
  connectedCallback() {
703
- const append = this.querySelector("[slot=append]");
704
- const prepend = this.querySelector("[slot=prepend]");
705
719
  this.multiline = this.hasAttribute("multiline") || false;
706
- this.value = this.getAttribute("value");
720
+ this.value = this.getAttribute("value") || "";
707
721
  this.type = this.getAttribute("type") || "text";
708
722
  this.placeholder = this.getAttribute("placeholder");
709
723
 
@@ -715,19 +729,23 @@ class FigInputText extends HTMLElement {
715
729
  html = `<textarea
716
730
  placeholder="${this.placeholder}">${this.value}</textarea>`;
717
731
  }
718
- this.innerHTML = html;
719
-
720
- if (prepend) {
721
- prepend.addEventListener("click", this.focus.bind(this));
722
- this.prepend(prepend);
723
- }
724
- if (append) {
725
- append.addEventListener("click", this.focus.bind(this));
726
- this.append(append);
727
- }
728
732
 
729
733
  //child nodes hack
730
734
  requestAnimationFrame(() => {
735
+ const append = this.querySelector("[slot=append]");
736
+ const prepend = this.querySelector("[slot=prepend]");
737
+
738
+ this.innerHTML = html;
739
+
740
+ if (prepend) {
741
+ prepend.addEventListener("click", this.focus.bind(this));
742
+ this.prepend(prepend);
743
+ }
744
+ if (append) {
745
+ append.addEventListener("click", this.focus.bind(this));
746
+ this.append(append);
747
+ }
748
+
731
749
  this.input = this.querySelector("input,textarea");
732
750
 
733
751
  if (this.getAttribute("min")) {
@@ -778,6 +796,55 @@ class FigInputText extends HTMLElement {
778
796
  }
779
797
  window.customElements.define("fig-input-text", FigInputText);
780
798
 
799
+ /* Avatar */
800
+ class FigAvatar extends HTMLElement {
801
+ constructor() {
802
+ super();
803
+ }
804
+ connectedCallback() {
805
+ this.src = this.getAttribute("src");
806
+ this.name = this.getAttribute("name");
807
+ this.initials = this.getInitials(this.name);
808
+ this.setAttribute("initials", this.initials);
809
+ this.setSrc(this.src);
810
+ requestAnimationFrame(() => {
811
+ this.img = this.querySelector("img");
812
+ });
813
+ }
814
+ setSrc(src) {
815
+ this.src = src;
816
+ if (src) {
817
+ this.innerHTML = `<img src="${this.src}" ${
818
+ this.name ? `alt="${this.name}"` : ""
819
+ } />`;
820
+ }
821
+ }
822
+ getInitials(name) {
823
+ return name
824
+ ? name
825
+ .split(" ")
826
+ .map((n) => n[0])
827
+ .join("")
828
+ : "";
829
+ }
830
+ static get observedAttributes() {
831
+ return ["src", "href", "name"];
832
+ }
833
+ attributeChangedCallback(name, oldValue, newValue) {
834
+ this[name] = newValue;
835
+ if (name === "name") {
836
+ this.img?.setAttribute("alt", newValue);
837
+ this.name = newValue;
838
+ this.initials = this.getInitials(this.name);
839
+ this.setAttribute("initials", this.initials);
840
+ } else if (name === "src") {
841
+ this.src = newValue;
842
+ this.setSrc(this.src);
843
+ }
844
+ }
845
+ }
846
+ window.customElements.define("fig-avatar", FigAvatar);
847
+
781
848
  /* Form Field */
782
849
  class FigField extends HTMLElement {
783
850
  constructor() {
@@ -851,26 +918,28 @@ class FigInputColor extends HTMLElement {
851
918
 
852
919
  this.style.setProperty("--alpha", this.#rgba.a);
853
920
 
854
- this.#swatch = this.querySelector("[type=color]");
855
- this.textInput = this.querySelector("[type=text]");
856
- this.#alphaInput = this.querySelector("[type=number]");
921
+ requestAnimationFrame(() => {
922
+ this.#swatch = this.querySelector("[type=color]");
923
+ this.textInput = this.querySelector("[type=text]");
924
+ this.#alphaInput = this.querySelector("[type=number]");
857
925
 
858
- this.#swatch.disabled = this.hasAttribute("disabled");
859
- this.#swatch.addEventListener("input", this.handleInput.bind(this));
926
+ this.#swatch.disabled = this.hasAttribute("disabled");
927
+ this.#swatch.addEventListener("input", this.handleInput.bind(this));
860
928
 
861
- if (this.textInput) {
862
- this.textInput.value = this.#swatch.value = this.rgbAlphaToHex(
863
- this.#rgba,
864
- 1
865
- );
866
- }
929
+ if (this.textInput) {
930
+ this.textInput.value = this.#swatch.value = this.rgbAlphaToHex(
931
+ this.#rgba,
932
+ 1
933
+ );
934
+ }
867
935
 
868
- if (this.#alphaInput) {
869
- this.#alphaInput.addEventListener(
870
- "input",
871
- this.handleAlphaInput.bind(this)
872
- );
873
- }
936
+ if (this.#alphaInput) {
937
+ this.#alphaInput.addEventListener(
938
+ "input",
939
+ this.handleAlphaInput.bind(this)
940
+ );
941
+ }
942
+ });
874
943
  }
875
944
  handleAlphaInput(event) {
876
945
  //do not propagate to onInput handler for web component
@@ -1123,3 +1192,94 @@ class FigSwitch extends FigCheckbox {
1123
1192
  }
1124
1193
  }
1125
1194
  window.customElements.define("fig-switch", FigSwitch);
1195
+
1196
+ /* Bell */
1197
+ class FigBell extends HTMLElement {
1198
+ constructor() {
1199
+ super();
1200
+ }
1201
+ }
1202
+ window.customElements.define("fig-bell", FigBell);
1203
+
1204
+ /* Badge */
1205
+ class FigBadge extends HTMLElement {
1206
+ constructor() {
1207
+ super();
1208
+ }
1209
+ }
1210
+ window.customElements.define("fig-badge", FigBadge);
1211
+
1212
+ /* Accordion */
1213
+ class FigAccordion extends HTMLElement {
1214
+ constructor() {
1215
+ super();
1216
+ }
1217
+ }
1218
+ window.customElements.define("fig-accordion", FigAccordion);
1219
+
1220
+ /* Combo Input */
1221
+ class FigComboInput extends HTMLElement {
1222
+ constructor() {
1223
+ super();
1224
+ }
1225
+ getOptionsFromAttribute() {
1226
+ return (this.getAttribute("options") || "").split(",");
1227
+ }
1228
+ connectedCallback() {
1229
+ this.options = this.getOptionsFromAttribute();
1230
+ this.placeholder = this.getAttribute("placeholder") || "";
1231
+ this.value = this.getAttribute("value") || "";
1232
+ this.innerHTML = `<div class="input-combo">
1233
+ <fig-input-text placeholder="${this.placeholder}">
1234
+ </fig-input-text>
1235
+ <fig-button type="select" variant="input" icon>
1236
+ <svg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
1237
+ <path d='M5.87868 7.12132L8 9.24264L10.1213 7.12132' stroke='currentColor' stroke-opacity="0.5" stroke-linecap='round'/>
1238
+ </svg>
1239
+ <fig-dropdown type="dropdown">
1240
+ ${this.options
1241
+ .map((option) => `<option>${option}</option>`)
1242
+ .join("")}
1243
+ </fig-dropdown>
1244
+ </fig-button>
1245
+ </div>`;
1246
+ requestAnimationFrame(() => {
1247
+ this.input = this.querySelector("fig-input-text");
1248
+ this.dropdown = this.querySelector("fig-dropdown");
1249
+
1250
+ this.dropdown.addEventListener(
1251
+ "input",
1252
+ this.handleDropdownChange.bind(this)
1253
+ );
1254
+ });
1255
+ }
1256
+ handleDropdownChange(e) {
1257
+ console.log(e.target.value);
1258
+ this.value = e.target.value;
1259
+ this.setAttribute("value", this.value);
1260
+ }
1261
+ handleInput(e) {
1262
+ this.value = this.input.value;
1263
+ }
1264
+ static get observedAttributes() {
1265
+ return ["options", "placeholder", "value"];
1266
+ }
1267
+ attributeChangedCallback(name, oldValue, newValue) {
1268
+ if (name === "options") {
1269
+ this.options = newValue.split(",");
1270
+ if (this.dropdown) {
1271
+ this.dropdown.innerHTML = this.options
1272
+ .map((option) => `<option>${option}</option>`)
1273
+ .join("");
1274
+ }
1275
+ }
1276
+ if (name === "placeholder") {
1277
+ this.placeholder = newValue;
1278
+ }
1279
+ if (name === "value") {
1280
+ this.value = newValue;
1281
+ this.input.setAttribute("value", newValue);
1282
+ }
1283
+ }
1284
+ }
1285
+ window.customElements.define("fig-combo-input", FigComboInput);
package/package.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "1.0.36"
3
+ "version": "1.0.38"
4
4
  }