@rogieking/figui3 6.4.6 → 6.4.7

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/fig-lab.css CHANGED
@@ -18,7 +18,8 @@ fig-field-slider {
18
18
 
19
19
 
20
20
  &:focus-within {
21
- outline: 1px solid var(--figma-color-border-selected);
21
+ outline: var(--figma-focus-outline);
22
+ outline-offset: var(--figma-focus-outline-offset);
22
23
  }
23
24
 
24
25
  label {
@@ -86,8 +87,8 @@ fig-field-slider {
86
87
  --slider-tick-opacity: 1;
87
88
 
88
89
  &:has(input[type="range"]:focus-within) {
89
- --slider-thumb-outline: 1.5px solid var(--figma-color-border-selected) !important;
90
- --slider-thumb-outline-offset: 2px !important;
90
+ --slider-thumb-outline: var(--figma-focus-outline) !important;
91
+ --slider-thumb-outline-offset: var(--figma-focus-outline-offset) !important;
91
92
  }
92
93
 
93
94
  .fig-slider-input-container {
@@ -170,7 +171,8 @@ fig-field-slider {
170
171
  box-shadow: none !important;
171
172
  }
172
173
  &:has(input:focus) {
173
- box-shadow: inset 0 0 0 1px var(--figma-color-border-selected) !important;
174
+ outline: var(--figma-focus-outline) !important;
175
+ outline-offset: var(--figma-focus-outline-offset) !important;
174
176
  }
175
177
  input {
176
178
  field-sizing: content;
@@ -218,6 +220,29 @@ fig-canvas-control {
218
220
  z-index: 1;
219
221
  }
220
222
 
223
+ fig-handle{
224
+ &[type="color"]{
225
+ --width: 0.75rem;
226
+ --height: 0.75rem;
227
+ --fig-handle-padding: 1px;
228
+ --fig-handle-shadow: none;
229
+ &:hover,
230
+ &:focus-within,
231
+ &[selected]:not([selected="false"]){
232
+ --width: 1rem;
233
+ --height: 1rem;
234
+ --fig-handle-outline-color: transparent;
235
+ }
236
+ &.dragging,
237
+ &:active{
238
+ --fig-handle-padding: 2px !important;
239
+ }
240
+ &[selected]:not([selected="false"]){
241
+ --fig-handle-padding: 1px;
242
+ }
243
+ }
244
+ }
245
+
221
246
  fig-handle:hover,
222
247
  fig-handle:hover .fig-handle-hit-area {
223
248
  cursor: var(--fig-lab-cursor) !important;
@@ -340,7 +365,10 @@ fig-input-angle {
340
365
  background-color: var(--figma-color-bg-secondary);
341
366
  border-radius: 100%;
342
367
  box-shadow: inset 0 0 0 1px var(--figma-color-border);
343
- &:focus,
368
+ &:focus {
369
+ outline: var(--figma-focus-outline);
370
+ outline-offset: var(--figma-focus-outline-offset);
371
+ }
344
372
  &.dragging {
345
373
  outline: 0;
346
374
  box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
package/fig-layer.css ADDED
@@ -0,0 +1,111 @@
1
+ /* Layer */
2
+ fig-layer {
3
+ --indent: var(--spacer-3);
4
+ display: block;
5
+ color: var(--figma-color-text);
6
+ position: relative;
7
+ user-select: none;
8
+ width: 100%;
9
+ padding: 0 var(--spacer-3);
10
+ border-radius: var(--radius-medium);
11
+ }
12
+
13
+ fig-layer:has(fig-layer) > .fig-layer-row > .fig-layer-chevron {
14
+ visibility: visible;
15
+ }
16
+
17
+ fig-layer > .fig-layer-row {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: var(--spacer-1);
21
+ padding: var(--spacer-1) var(--spacer-2);
22
+ height: var(--spacer-4);
23
+ border-radius: var(--radius-medium);
24
+ position: relative;
25
+ }
26
+
27
+ fig-layer > .fig-layer-row .fig-layer-chevron {
28
+ mask-image: var(--icon-16-chevron);
29
+ mask-size: contain;
30
+ mask-repeat: no-repeat;
31
+ mask-position: center;
32
+ display: flex;
33
+ visibility: hidden;
34
+ background: var(--figma-color-text-tertiary);
35
+ width: var(--spacer-3);
36
+ height: var(--spacer-3);
37
+ flex-shrink: 0;
38
+ transition: transform 0.15s;
39
+ position: absolute;
40
+ left: calc(var(--spacer-3) * -1);
41
+ top: var(--spacer-1);
42
+ rotate: -90deg;
43
+ }
44
+
45
+ fig-layer > .fig-layer-row:hover {
46
+ background: var(--figma-color-bg-secondary);
47
+ }
48
+
49
+ fig-layer > .fig-layer-row:hover .fig-layer-actions {
50
+ opacity: 1;
51
+ }
52
+
53
+ fig-layer > .fig-layer-row .fig-layer-icon {
54
+ flex-shrink: 0;
55
+ width: var(--spacer-3);
56
+ height: var(--spacer-3);
57
+ color: var(--figma-color-icon-tertiary);
58
+ margin-left: calc(var(--spacer-1) * -1);
59
+ }
60
+
61
+ fig-layer > .fig-layer-row > label {
62
+ flex: 1;
63
+ min-width: 0;
64
+ overflow: hidden;
65
+ text-overflow: ellipsis;
66
+ white-space: nowrap;
67
+ color: var(--figma-color-text);
68
+ }
69
+
70
+ fig-layer .fig-layer-actions {
71
+ display: flex;
72
+ margin-right: calc(-1 * var(--spacer-1));
73
+ gap: 0;
74
+ opacity: 0;
75
+ transition: opacity 0.15s;
76
+ flex-shrink: 0;
77
+ }
78
+
79
+ fig-layer .fig-layer-actions > * {
80
+ flex-shrink: 0;
81
+ }
82
+
83
+ fig-layer > fig-layer {
84
+ padding: 0;
85
+ margin-top: 1px;
86
+ }
87
+
88
+ fig-layer > fig-layer .fig-layer-row {
89
+ padding-left: var(--indent);
90
+ }
91
+
92
+ fig-layer:not([open]) > fig-layer,
93
+ fig-layer[open="false"] > fig-layer {
94
+ display: none;
95
+ }
96
+
97
+ fig-layer[open]:not([open="false"]) > .fig-layer-row > .fig-layer-chevron {
98
+ rotate: 0deg;
99
+ }
100
+
101
+ fig-layer[visible="false"] > .fig-layer-row > label {
102
+ color: var(--figma-color-text-tertiary);
103
+ }
104
+
105
+ fig-layer[selected]:not([selected="false"]) > .fig-layer-row {
106
+ background: var(--figma-color-bg-selected);
107
+ }
108
+
109
+ fig-layer[selected]:not([selected="false"]) > .fig-layer-row > .fig-layer-icon {
110
+ color: var(--figma-color-icon);
111
+ }
package/fig-layer.js ADDED
@@ -0,0 +1,155 @@
1
+ // FigLayer
2
+ class FigLayer extends HTMLElement {
3
+ static get observedAttributes() {
4
+ return ["open", "visible", "disabled"];
5
+ }
6
+
7
+ #chevron = null;
8
+ #boundHandleChevronClick = null;
9
+
10
+ connectedCallback() {
11
+ this.#syncA11y();
12
+ requestAnimationFrame(() => {
13
+ this.#injectChevron();
14
+ this.#syncA11y();
15
+ });
16
+ }
17
+
18
+ disconnectedCallback() {
19
+ if (this.#chevron && this.#boundHandleChevronClick) {
20
+ this.#chevron.removeEventListener("click", this.#boundHandleChevronClick);
21
+ this.#chevron.removeEventListener("keydown", this.#handleChevronKeyDown);
22
+ }
23
+ }
24
+
25
+ #injectChevron() {
26
+ const row = this.querySelector(":scope > .fig-layer-row");
27
+ if (!row) return;
28
+
29
+ if (row.querySelector(".fig-layer-chevron")) return;
30
+
31
+ this.#chevron = document.createElement("span");
32
+ this.#chevron.className = "fig-layer-chevron";
33
+ row.prepend(this.#chevron);
34
+
35
+ this.#boundHandleChevronClick = this.#handleChevronClick.bind(this);
36
+ this.#chevron.addEventListener("click", this.#boundHandleChevronClick);
37
+ this.#chevron.addEventListener("keydown", this.#handleChevronKeyDown);
38
+ this.#syncA11y();
39
+ }
40
+
41
+ #handleChevronClick(e) {
42
+ if (this.disabled) return;
43
+ e.stopPropagation();
44
+ this.open = !this.open;
45
+ }
46
+
47
+ #handleChevronKeyDown = (e) => {
48
+ if (e.key !== "Enter" && e.key !== " ") return;
49
+ e.preventDefault();
50
+ this.#handleChevronClick(e);
51
+ };
52
+
53
+ #syncA11y() {
54
+ if (!this.hasAttribute("role")) this.setAttribute("role", "treeitem");
55
+ if (!this.hasAttribute("tabindex")) {
56
+ this.setAttribute("tabindex", this.disabled ? "-1" : "0");
57
+ }
58
+ this.setAttribute("aria-expanded", this.open ? "true" : "false");
59
+ this.setAttribute("aria-hidden", this.visible ? "false" : "true");
60
+ this.setAttribute("aria-disabled", this.disabled ? "true" : "false");
61
+
62
+ if (!this.#chevron) return;
63
+ this.#chevron.setAttribute("role", "button");
64
+ this.#chevron.setAttribute("tabindex", this.disabled ? "-1" : "0");
65
+ this.#chevron.setAttribute(
66
+ "aria-label",
67
+ this.open ? "Collapse layer" : "Expand layer",
68
+ );
69
+ this.#chevron.setAttribute("aria-expanded", this.open ? "true" : "false");
70
+ this.#chevron.setAttribute("aria-disabled", this.disabled ? "true" : "false");
71
+ }
72
+
73
+ get open() {
74
+ const attr = this.getAttribute("open");
75
+ return attr !== null && attr !== "false";
76
+ }
77
+
78
+ set open(value) {
79
+ const oldValue = this.open;
80
+ if (value) {
81
+ this.setAttribute("open", "true");
82
+ } else {
83
+ this.setAttribute("open", "false");
84
+ }
85
+ if (oldValue !== value) {
86
+ this.dispatchEvent(
87
+ new CustomEvent("openchange", {
88
+ detail: { open: value },
89
+ bubbles: true,
90
+ }),
91
+ );
92
+ }
93
+ }
94
+
95
+ get visible() {
96
+ const attr = this.getAttribute("visible");
97
+ return attr !== "false";
98
+ }
99
+
100
+ set visible(value) {
101
+ const oldValue = this.visible;
102
+ if (value) {
103
+ this.setAttribute("visible", "true");
104
+ } else {
105
+ this.setAttribute("visible", "false");
106
+ }
107
+ if (oldValue !== value) {
108
+ this.dispatchEvent(
109
+ new CustomEvent("visibilitychange", {
110
+ detail: { visible: value },
111
+ bubbles: true,
112
+ }),
113
+ );
114
+ }
115
+ }
116
+
117
+ get disabled() {
118
+ const attr = this.getAttribute("disabled");
119
+ return attr !== null && attr !== "false";
120
+ }
121
+
122
+ attributeChangedCallback(name, oldValue, newValue) {
123
+ if (oldValue === newValue) return;
124
+
125
+ if (name === "open") {
126
+ this.#syncA11y();
127
+ const isOpen = newValue !== null && newValue !== "false";
128
+ this.dispatchEvent(
129
+ new CustomEvent("openchange", {
130
+ detail: { open: isOpen },
131
+ bubbles: true,
132
+ }),
133
+ );
134
+ }
135
+
136
+ if (name === "visible") {
137
+ this.#syncA11y();
138
+ const isVisible = newValue !== "false";
139
+ this.dispatchEvent(
140
+ new CustomEvent("visibilitychange", {
141
+ detail: { visible: isVisible },
142
+ bubbles: true,
143
+ }),
144
+ );
145
+ }
146
+
147
+ if (name === "disabled") {
148
+ this.#syncA11y();
149
+ }
150
+ }
151
+ }
152
+
153
+ if (!customElements.get("fig-layer")) {
154
+ customElements.define("fig-layer", FigLayer);
155
+ }