@rogieking/figui3 1.0.63 → 1.0.65

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 +139 -0
  2. package/fig.css +78 -39
  3. package/fig.js +132 -94
  4. package/package.json +1 -1
package/example.html CHANGED
@@ -16,6 +16,83 @@
16
16
  <fig-header>
17
17
  <h3>UI3 Components</h3>
18
18
  </fig-header>
19
+ <br />
20
+ <fig-field direction="horizontal">
21
+ <label>Opacity</label>
22
+ <fig-slider type="opacity"
23
+ full
24
+ value="0.75"
25
+ color="#ff0000"
26
+ units="%"
27
+ text="true"></fig-slider>
28
+ <fig-button variant="ghost"
29
+ type="toggle"
30
+ icon="true">
31
+ <svg class="svg"
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ width="16"
34
+ height="16"
35
+ viewBox="0 0 16 16">
36
+ <path fill="currentColor"
37
+ fill-opacity="1"
38
+ fill-rule="evenodd"
39
+ stroke="none"
40
+ 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">
41
+ </path>
42
+ </svg>
43
+ </fig-button>
44
+ </fig-field>
45
+ <br />
46
+ <fig-field direction="horizontal">
47
+ <label>Blend mode</label>
48
+ <fig-dropdown full
49
+ type="dropdown">
50
+ <option>One</option>
51
+ <option>Two</option>
52
+ </fig-dropdown>
53
+ <fig-button variant="ghost"
54
+ type="toggle"
55
+ icon="true">
56
+ <svg class="svg"
57
+ xmlns="http://www.w3.org/2000/svg"
58
+ width="16"
59
+ height="16"
60
+ viewBox="0 0 16 16">
61
+ <path fill="currentColor"
62
+ fill-opacity="1"
63
+ fill-rule="evenodd"
64
+ stroke="none"
65
+ 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">
66
+ </path>
67
+ </svg>
68
+ </fig-button>
69
+ </fig-field>
70
+ <br />
71
+ <fig-field direction="horizontal">
72
+ <label>Description</label>
73
+ <fig-input-text multiline="true"
74
+ value=""
75
+ full
76
+ autoresize="true"
77
+ resizable="true"
78
+ placeholder="Anthropic API key"></fig-input-text>
79
+ <fig-button variant="ghost"
80
+ type="toggle"
81
+ icon="true">
82
+ <svg class="svg"
83
+ xmlns="http://www.w3.org/2000/svg"
84
+ width="16"
85
+ height="16"
86
+ viewBox="0 0 16 16">
87
+ <path fill="currentColor"
88
+ fill-opacity="1"
89
+ fill-rule="evenodd"
90
+ stroke="none"
91
+ 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">
92
+ </path>
93
+ </svg>
94
+ </fig-button>
95
+ </fig-field>
19
96
  <fig-avatar src="https://avatars.githubusercontent.com/u/12345678?v=4"
20
97
  name="John Doe"></fig-avatar>
21
98
  <fig-avatar size="large"
@@ -47,6 +124,68 @@
47
124
  <fig-button>Primary</fig-button>
48
125
  <fig-button variant="secondary">Secondary</fig-button>
49
126
  <fig-button variant="ghost">Ghost</fig-button>
127
+
128
+ <fig-button-combo>
129
+ <fig-button>Primary</fig-button>
130
+ <fig-button icon="true"
131
+ type="select">
132
+ <svg width="24"
133
+ height="24"
134
+ viewBox="0 0 24 24"
135
+ fill="none"
136
+ xmlns="http://www.w3.org/2000/svg">
137
+ <path fill-rule="evenodd"
138
+ clip-rule="evenodd"
139
+ d="M9.64645 11.1464C9.84171 10.9512 10.1583 10.9512 10.3536 11.1464L12 12.7929L13.6464 11.1464C13.8417 10.9512 14.1583 10.9512 14.3536 11.1464C14.5488 11.3417 14.5488 11.6583 14.3536 11.8536L12.3536 13.8536C12.1583 14.0488 11.8417 14.0488 11.6464 13.8536L9.64645 11.8536C9.45118 11.6583 9.45118 11.3417 9.64645 11.1464Z"
140
+ fill="currentColor"
141
+ fill-opacity="0.9" />
142
+ </svg>
143
+ <fig-dropdown>
144
+ <option>One</option>
145
+ <option>Two</option>
146
+ </fig-dropdown>
147
+ </fig-button>
148
+ </fig-button-combo>
149
+ <fig-button-combo>
150
+ <fig-button variant="secondary">Secondary</fig-button>
151
+ <fig-button variant="secondary"
152
+ icon="true"
153
+ type="select">
154
+ <svg width="24"
155
+ height="24"
156
+ viewBox="0 0 24 24"
157
+ fill="none"
158
+ xmlns="http://www.w3.org/2000/svg">
159
+ <path fill-rule="evenodd"
160
+ clip-rule="evenodd"
161
+ d="M9.64645 11.1464C9.84171 10.9512 10.1583 10.9512 10.3536 11.1464L12 12.7929L13.6464 11.1464C13.8417 10.9512 14.1583 10.9512 14.3536 11.1464C14.5488 11.3417 14.5488 11.6583 14.3536 11.8536L12.3536 13.8536C12.1583 14.0488 11.8417 14.0488 11.6464 13.8536L9.64645 11.8536C9.45118 11.6583 9.45118 11.3417 9.64645 11.1464Z"
162
+ fill="currentColor"
163
+ fill-opacity="0.9" />
164
+ </svg>
165
+ <fig-dropdown>
166
+ <option>One</option>
167
+ <option>Two</option>
168
+ </fig-dropdown>
169
+ </fig-button>
170
+ </fig-button-combo>
171
+ <fig-button icon="true"
172
+ type="select">
173
+ <svg width="24"
174
+ height="24"
175
+ viewBox="0 0 24 24"
176
+ fill="none"
177
+ xmlns="http://www.w3.org/2000/svg">
178
+ <path fill-rule="evenodd"
179
+ clip-rule="evenodd"
180
+ d="M9.64645 11.1464C9.84171 10.9512 10.1583 10.9512 10.3536 11.1464L12 12.7929L13.6464 11.1464C13.8417 10.9512 14.1583 10.9512 14.3536 11.1464C14.5488 11.3417 14.5488 11.6583 14.3536 11.8536L12.3536 13.8536C12.1583 14.0488 11.8417 14.0488 11.6464 13.8536L9.64645 11.8536C9.45118 11.6583 9.45118 11.3417 9.64645 11.1464Z"
181
+ fill="currentColor"
182
+ fill-opacity="0.9" />
183
+ </svg>
184
+ <fig-dropdown>
185
+ <option>One</option>
186
+ <option>Two</option>
187
+ </fig-dropdown>
188
+ </fig-button>
50
189
  <fig-button type="select">
51
190
  Select
52
191
  <fig-dropdown>
package/fig.css CHANGED
@@ -602,17 +602,22 @@ select {
602
602
  padding-right: 1.5rem;
603
603
  }
604
604
 
605
- fig-dropdown:has([trigger]) {
606
- & select {
607
- opacity: 0;
608
- position: absolute;
609
- inset: 0;
610
- }
605
+ fig-dialog > *:not(dialog) {
606
+ display: none !important;
611
607
  }
612
608
 
613
- fig-dialog > *:not(dialog),
614
- fig-dropdown > *:not(select) {
615
- display: none !important;
609
+ /* Dropdown */
610
+ fig-dropdown,
611
+ .fig-dropdown {
612
+ display: inline-flex;
613
+ position: relative;
614
+
615
+ & > *:not(select) {
616
+ display: none !important;
617
+ }
618
+ > select {
619
+ display: block;
620
+ }
616
621
  }
617
622
 
618
623
  /* Button */
@@ -705,23 +710,7 @@ fig-button {
705
710
  padding: 0;
706
711
  flex-grow: 0;
707
712
  flex-shrink: 0;
708
-
709
- &:hover {
710
- background-color: var(--figma-color-bg-ghost-hover);
711
- }
712
- }
713
-
714
- /* Upload */
715
- &[upload],
716
- &[upload] > button {
717
- position: relative;
718
-
719
- & input[type="file"] {
720
- opacity: 0;
721
- position: absolute;
722
- inset: 0;
723
- appearance: none;
724
- }
713
+ flex-basis: var(--spacer-4);
725
714
  }
726
715
 
727
716
  /* Disabled */
@@ -763,6 +752,7 @@ fig-button {
763
752
  &[type="select"],
764
753
  &[type="upload"] {
765
754
  position: relative;
755
+ overflow: hidden;
766
756
  > select,
767
757
  > input,
768
758
  > fig-dropdown {
@@ -1090,6 +1080,46 @@ fig-image {
1090
1080
  }
1091
1081
  }
1092
1082
 
1083
+ /* Combo button */
1084
+ .fig-button-combo,
1085
+ fig-button-combo,
1086
+ .fig-input-combo,
1087
+ fig-input-combo {
1088
+ display: inline-flex;
1089
+ flex-wrap: nowrap;
1090
+ align-items: center;
1091
+ gap: 0px;
1092
+ & > * {
1093
+ &:first-child,
1094
+ &:first-child > * {
1095
+ border-top-right-radius: 0;
1096
+ border-bottom-right-radius: 0;
1097
+ }
1098
+
1099
+ &:last-child,
1100
+ &:last-child > * {
1101
+ border-top-left-radius: 0;
1102
+ border-bottom-left-radius: 0;
1103
+ }
1104
+
1105
+ &:not(:last-child):not(:first-child),
1106
+ &:not(:last-child):not(:first-child) > * {
1107
+ border-radius: 0;
1108
+ }
1109
+ }
1110
+ }
1111
+ .fig-button-combo,
1112
+ fig-button-combo {
1113
+ > *:not(:first-child) {
1114
+ border-left: 1px solid var(--figma-color-bg-brand-hover);
1115
+ margin-left: -1px;
1116
+ }
1117
+ > *[variant="secondary"]:not(:first-child) {
1118
+ border-left: transparent;
1119
+ margin-left: -1px;
1120
+ }
1121
+ }
1122
+
1093
1123
  /* Combo input */
1094
1124
  .input-combo {
1095
1125
  display: inline-flex;
@@ -1857,7 +1887,6 @@ fig-content,
1857
1887
  fig-slider,
1858
1888
  fig-switch,
1859
1889
  fig-input-color,
1860
- fig-input-text,
1861
1890
  fig-checkbox,
1862
1891
  fig-radio,
1863
1892
  fig-tab,
@@ -1872,22 +1901,29 @@ fig-tabs {
1872
1901
  }
1873
1902
  }
1874
1903
 
1904
+ /* Text input */
1875
1905
  fig-input-text {
1906
+ display: inline-flex;
1876
1907
  user-select: all;
1877
1908
  gap: 0;
1878
1909
 
1879
1910
  &[multiline] {
1880
1911
  display: block;
1881
1912
  }
1882
- }
1883
-
1884
- fig-input-text[autoresize] textarea,
1885
- fig-input-text[autoresize] input {
1886
- field-sizing: content;
1887
- }
1888
-
1889
- fig-input-text[resizable] textarea {
1890
- resize: both;
1913
+ &[autoresize] input,
1914
+ &[autoresize] textarea {
1915
+ field-sizing: content;
1916
+ }
1917
+ &[resizable] input,
1918
+ &[resizable] textarea {
1919
+ resize: both;
1920
+ }
1921
+ &[resizable]:has(textarea[style*="width"]),
1922
+ &[resizable]:has(textarea[style*="height"]),
1923
+ &[resizable]:has(input[style*="width"]),
1924
+ &[resizable]:has(input[style*="height"]) {
1925
+ flex: unset;
1926
+ }
1891
1927
  }
1892
1928
 
1893
1929
  fig-checkbox,
@@ -1936,15 +1972,18 @@ vstack,
1936
1972
  [vstack] {
1937
1973
  display: flex;
1938
1974
  flex-direction: column;
1939
- gap: 0.5rem;
1975
+ align-items: start;
1976
+ gap: var(--spacer-2);
1977
+ flex-wrap: wrap;
1940
1978
  }
1941
1979
 
1942
1980
  hstack,
1943
1981
  .hstack,
1944
1982
  [hstack] {
1945
1983
  display: flex;
1946
- gap: 0.5rem;
1984
+ gap: var(--spacer-2);
1947
1985
  align-items: start;
1986
+ flex-wrap: nowrap;
1948
1987
  }
1949
1988
 
1950
1989
  fig-input-text {
@@ -2035,7 +2074,7 @@ fig-field,
2035
2074
  flex-direction: column;
2036
2075
  gap: 0;
2037
2076
 
2038
- & > * {
2077
+ & > [full] {
2039
2078
  flex: 1;
2040
2079
  }
2041
2080
 
package/fig.js CHANGED
@@ -5,20 +5,21 @@ function supportsPopover() {
5
5
  return HTMLElement.prototype.hasOwnProperty("popover");
6
6
  }
7
7
 
8
- /* Button */
9
- class FigButton extends HTMLElement {
10
- #type;
11
- #selected;
12
- constructor() {
13
- super();
14
- this.attachShadow({ mode: "open" });
15
- }
16
- connectedCallback() {
17
- this.render();
18
- }
19
- render() {
20
- this.#type = this.getAttribute("type") || "button";
21
- this.shadowRoot.innerHTML = `
8
+ if (window.customElements && !window.customElements.get("fig-button")) {
9
+ /* Button */
10
+ class FigButton extends HTMLElement {
11
+ #type;
12
+ #selected;
13
+ constructor() {
14
+ super();
15
+ this.attachShadow({ mode: "open" });
16
+ }
17
+ connectedCallback() {
18
+ this.render();
19
+ }
20
+ render() {
21
+ this.#type = this.getAttribute("type") || "button";
22
+ this.shadowRoot.innerHTML = `
22
23
  <style>
23
24
  button, button:hover, button:active {
24
25
  padding: 0 var(--spacer-2);
@@ -43,108 +44,143 @@ class FigButton extends HTMLElement {
43
44
  </button>
44
45
  `;
45
46
 
46
- this.#selected =
47
- this.hasAttribute("selected") &&
48
- this.getAttribute("selected") !== "false";
49
- this.addEventListener("click", this.handleClick.bind(this));
47
+ this.#selected =
48
+ this.hasAttribute("selected") &&
49
+ this.getAttribute("selected") !== "false";
50
+ this.addEventListener("click", this.handleClick.bind(this));
50
51
 
51
- this.button = this.querySelector("button");
52
- }
53
- get type() {
54
- return this.#type;
55
- }
56
- set type(value) {
57
- this.#type = value;
58
- this.button.type = value;
59
- this.setAttribute("type", value);
60
- }
61
- get selected() {
62
- return this.#selected;
63
- }
64
- set selected(value) {
65
- this.#selected = value;
66
- this.setAttribute("selected", value);
67
- }
52
+ this.button = this.querySelector("button");
53
+ }
54
+ get type() {
55
+ return this.#type;
56
+ }
57
+ set type(value) {
58
+ this.#type = value;
59
+ this.button.type = value;
60
+ this.setAttribute("type", value);
61
+ }
62
+ get selected() {
63
+ return this.#selected;
64
+ }
65
+ set selected(value) {
66
+ this.#selected = value;
67
+ this.setAttribute("selected", value);
68
+ }
68
69
 
69
- handleClick(event) {
70
- if (this.#type === "toggle") {
71
- this.selected = !this.#selected;
70
+ handleClick(event) {
71
+ if (this.#type === "toggle") {
72
+ this.selected = !this.#selected;
73
+ }
74
+ if (this.#type === "submit") {
75
+ this.button.click();
76
+ }
72
77
  }
73
- if (this.#type === "submit") {
74
- this.button.click();
78
+ static get observedAttributes() {
79
+ return ["disabled"];
75
80
  }
76
- }
77
- static get observedAttributes() {
78
- return ["disabled"];
79
- }
80
- attributeChangedCallback(name, oldValue, newValue) {
81
- if (this.button) {
82
- this.button[name] = newValue;
83
- if (newValue === "false") {
84
- this.button.removeAttribute(name);
81
+ attributeChangedCallback(name, oldValue, newValue) {
82
+ if (this.button) {
83
+ this.button[name] = newValue;
84
+ if (newValue === "false") {
85
+ this.button.removeAttribute(name);
86
+ }
85
87
  }
86
88
  }
87
89
  }
90
+ window.customElements.define("fig-button", FigButton);
88
91
  }
89
- window.customElements.define("fig-button", FigButton);
90
92
 
91
- /* Dropdown */
92
- class FigDropdown extends HTMLElement {
93
- constructor() {
94
- super();
95
- this.attachShadow({ mode: "open" });
96
- }
93
+ if (window.customElements && !window.customElements.get("fig-dropdown")) {
94
+ /* Dropdown */
95
+ class FigDropdown extends HTMLElement {
96
+ constructor() {
97
+ super();
98
+ this.select = document.createElement("select");
99
+ this.optionsSlot = document.createElement("slot");
100
+ this.attachShadow({ mode: "open" });
101
+ }
97
102
 
98
- connectedCallback() {
99
- this.type = this.getAttribute("type") || "select";
100
- this.value = this.getAttribute("value") || "";
103
+ connectedCallback() {
104
+ this.type = this.getAttribute("type") || "select";
105
+ this.value = this.getAttribute("value") || "";
101
106
 
102
- this.select = document.createElement("select");
103
- this.optionsSlot = document.createElement("slot");
104
- this.appendChild(this.select);
105
- this.shadowRoot.appendChild(this.optionsSlot);
107
+ this.appendChild(this.select);
108
+ this.shadowRoot.appendChild(this.optionsSlot);
106
109
 
107
- this.optionsSlot.addEventListener("slotchange", this.slotChange.bind(this));
110
+ this.optionsSlot.addEventListener(
111
+ "slotchange",
112
+ this.slotChange.bind(this)
113
+ );
108
114
 
109
- this.select.addEventListener("input", this.handleDropdownInput.bind(this));
110
- }
115
+ this.select.addEventListener(
116
+ "input",
117
+ this.handleDropdownInput.bind(this)
118
+ );
119
+ this.select.addEventListener(
120
+ "change",
121
+ this.handleDropdownChange.bind(this)
122
+ );
123
+ }
111
124
 
112
- slotChange() {
113
- while (this.select.firstChild) {
114
- this.select.firstChild.remove();
115
- }
116
- if (this.type === "dropdown") {
117
- const hiddenOption = document.createElement("option");
118
- hiddenOption.setAttribute("hidden", "true");
119
- hiddenOption.setAttribute("selected", "true");
120
- this.select.appendChild(hiddenOption);
121
- }
122
- this.optionsSlot.assignedNodes().forEach((option) => {
123
- if (option.nodeName === "OPTION" || option.nodeName === "OPTGROUP") {
124
- if (option.hasAttribute("value") && option.hasAttribute("selected")) {
125
- this.value = option.getAttribute("value");
125
+ slotChange() {
126
+ while (this.select.firstChild) {
127
+ this.select.firstChild.remove();
128
+ }
129
+ if (this.type === "dropdown") {
130
+ const hiddenOption = document.createElement("option");
131
+ hiddenOption.setAttribute("hidden", "true");
132
+ hiddenOption.setAttribute("selected", "true");
133
+ this.select.appendChild(hiddenOption);
134
+ }
135
+ this.optionsSlot.assignedNodes().forEach((option) => {
136
+ if (option.nodeName === "OPTION" || option.nodeName === "OPTGROUP") {
137
+ if (option.hasAttribute("value") && option.hasAttribute("selected")) {
138
+ this.value = option.getAttribute("value");
139
+ }
140
+ this.select.appendChild(option.cloneNode(true));
126
141
  }
127
- this.select.appendChild(option.cloneNode(true));
142
+ });
143
+ if (this.type === "dropdown") {
144
+ this.select.selectedIndex = -1;
128
145
  }
129
- });
130
- if (this.type === "dropdown") {
131
- this.select.selectedIndex = -1;
132
146
  }
133
- }
134
147
 
135
- handleDropdownInput() {
136
- if (this.type === "dropdown") {
148
+ handleDropdownInput() {
137
149
  this.value = this.select.value;
138
150
  this.setAttribute("value", this.value);
139
- this.select.selectedIndex = -1;
151
+ }
152
+ handleDropdownChange() {
153
+ if (this.type === "dropdown") {
154
+ this.select.selectedIndex = -1;
155
+ }
156
+ }
157
+ focus() {
158
+ this.select.focus();
159
+ }
160
+ blur() {
161
+ this.select.blur();
162
+ }
163
+ get value() {
164
+ return this.select?.value;
165
+ }
166
+ set value(value) {
167
+ this.setAttribute("value", value);
168
+ }
169
+ static get observedAttributes() {
170
+ return ["value", "type"];
171
+ }
172
+ attributeChangedCallback(name, oldValue, newValue) {
173
+ if (name === "value") {
174
+ this.select.value = newValue;
175
+ }
176
+ if (name === "type") {
177
+ this.type = newValue;
178
+ }
140
179
  }
141
180
  }
142
- focus() {
143
- this.select.focus();
144
- }
145
- }
146
181
 
147
- customElements.define("fig-dropdown", FigDropdown);
182
+ customElements.define("fig-dropdown", FigDropdown);
183
+ }
148
184
 
149
185
  /* Tooltip */
150
186
  class FigTooltip extends HTMLElement {
@@ -1391,7 +1427,9 @@ class FigImage extends HTMLElement {
1391
1427
  attributeChangedCallback(name, oldValue, newValue) {
1392
1428
  if (name === "src") {
1393
1429
  this.src = newValue;
1394
- this.chit.setAttribute("src", this.src);
1430
+ if (this.chit) {
1431
+ this.chit.setAttribute("src", this.src);
1432
+ }
1395
1433
  }
1396
1434
  if (name === "upload") {
1397
1435
  this.upload = newValue.toLowerCase() === "true";
package/package.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "1.0.63"
3
+ "version": "1.0.65"
4
4
  }