@rettangoli/ui 1.0.3 → 1.0.5

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.
@@ -0,0 +1,272 @@
1
+ import {
2
+ css,
3
+ dimensionWithUnit,
4
+ applyInlineWidthDimension,
5
+ } from "../common.js";
6
+ import cursorStyles from "../styles/cursorStyles.js";
7
+ import marginStyles from "../styles/marginStyles.js";
8
+ import tagSurfaceStyles from "../styles/tagSurfaceStyles.js";
9
+
10
+ class RettangoliTagElement extends HTMLElement {
11
+ static styleSheet = null;
12
+
13
+ static initializeStyleSheet() {
14
+ if (!RettangoliTagElement.styleSheet) {
15
+ RettangoliTagElement.styleSheet = new CSSStyleSheet();
16
+ RettangoliTagElement.styleSheet.replaceSync(css`
17
+ :host {
18
+ display: inline-flex;
19
+ min-width: 0;
20
+ }
21
+
22
+ slot {
23
+ display: contents;
24
+ }
25
+
26
+ .surface {
27
+ --rtgl-tag-icon-size: 12px;
28
+ --rtgl-tag-remove-size: 16px;
29
+ display: inline-flex;
30
+ align-items: center;
31
+ min-width: 0;
32
+ max-width: 100%;
33
+ width: 100%;
34
+ height: 24px;
35
+ padding-left: 10px;
36
+ padding-right: 10px;
37
+ gap: 6px;
38
+ box-sizing: border-box;
39
+ border: 1px solid var(--border);
40
+ border-radius: var(--tag-border-radius);
41
+ background-color: var(--muted);
42
+ color: var(--muted-foreground);
43
+ font-size: var(--xs-font-size);
44
+ font-weight: var(--xs-font-weight);
45
+ line-height: var(--xs-line-height);
46
+ letter-spacing: var(--xs-letter-spacing);
47
+ vertical-align: middle;
48
+ }
49
+
50
+ .surface rtgl-svg {
51
+ width: var(--rtgl-tag-icon-size);
52
+ height: var(--rtgl-tag-icon-size);
53
+ color: inherit;
54
+ flex-shrink: 0;
55
+ }
56
+
57
+ .label {
58
+ min-width: 0;
59
+ overflow: hidden;
60
+ text-overflow: ellipsis;
61
+ white-space: nowrap;
62
+ }
63
+
64
+ .removeButton {
65
+ position: relative;
66
+ appearance: none;
67
+ display: inline-flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ flex-shrink: 0;
71
+ width: var(--rtgl-tag-remove-size);
72
+ height: var(--rtgl-tag-remove-size);
73
+ padding: 0;
74
+ margin: 0;
75
+ border: 0;
76
+ border-radius: var(--border-radius-f);
77
+ background: transparent;
78
+ color: inherit;
79
+ opacity: 0.76;
80
+ }
81
+
82
+ .removeButton::before,
83
+ .removeButton::after {
84
+ content: "";
85
+ position: absolute;
86
+ width: calc(var(--rtgl-tag-icon-size) - 1px);
87
+ height: 1.5px;
88
+ border-radius: 1px;
89
+ background: currentColor;
90
+ }
91
+
92
+ .removeButton::before {
93
+ transform: rotate(45deg);
94
+ }
95
+
96
+ .removeButton::after {
97
+ transform: rotate(-45deg);
98
+ }
99
+
100
+ .removeButton:hover {
101
+ cursor: pointer;
102
+ opacity: 1;
103
+ background-color: color-mix(in srgb, currentColor 12%, transparent);
104
+ }
105
+
106
+ .removeButton:focus-visible {
107
+ outline: 2px solid color-mix(in srgb, currentColor 30%, transparent);
108
+ outline-offset: 1px;
109
+ opacity: 1;
110
+ }
111
+
112
+ ${tagSurfaceStyles}
113
+ :host .surface {
114
+ border-radius: var(--tag-border-radius) !important;
115
+ }
116
+ ${marginStyles}
117
+ ${cursorStyles}
118
+ `);
119
+ }
120
+ }
121
+
122
+ constructor() {
123
+ super();
124
+ RettangoliTagElement.initializeStyleSheet();
125
+
126
+ this.shadow = this.attachShadow({ mode: "open" });
127
+ this.shadow.adoptedStyleSheets = [RettangoliTagElement.styleSheet];
128
+
129
+ this._surfaceElement = document.createElement("span");
130
+ this._surfaceElement.className = "surface";
131
+ this._surfaceElement.setAttribute("part", "surface");
132
+
133
+ this._labelElement = document.createElement("span");
134
+ this._labelElement.className = "label";
135
+ this._labelElement.setAttribute("part", "label");
136
+
137
+ this._slotElement = document.createElement("slot");
138
+ this._labelElement.appendChild(this._slotElement);
139
+ this._surfaceElement.appendChild(this._labelElement);
140
+ this.shadow.appendChild(this._surfaceElement);
141
+
142
+ this._prefixIcon = null;
143
+ this._suffixIcon = null;
144
+ this._removeButton = null;
145
+ this._onRemoveClick = this._onRemoveClick.bind(this);
146
+ }
147
+
148
+ static get observedAttributes() {
149
+ return ["key", "pre", "suf", "removable", "w"];
150
+ }
151
+
152
+ connectedCallback() {
153
+ this._updateWidth();
154
+ this._updateStructure();
155
+ }
156
+
157
+ attributeChangedCallback(name, oldValue, newValue) {
158
+ if (name === "w") {
159
+ this._updateWidth();
160
+ return;
161
+ }
162
+
163
+ if (oldValue !== newValue) {
164
+ this._updateStructure();
165
+ }
166
+ }
167
+
168
+ _updateWidth() {
169
+ const width = dimensionWithUnit(this.getAttribute("w"));
170
+
171
+ applyInlineWidthDimension({
172
+ style: this.style,
173
+ width,
174
+ flexMinWidth: "0",
175
+ });
176
+ }
177
+
178
+ _createIconElement(className, part) {
179
+ const icon = document.createElement("rtgl-svg");
180
+ icon.className = className;
181
+ icon.setAttribute("part", part);
182
+ icon.setAttribute("aria-hidden", "true");
183
+ return icon;
184
+ }
185
+
186
+ _syncIcon({
187
+ iconName,
188
+ element,
189
+ className,
190
+ part,
191
+ insertBeforeElement,
192
+ }) {
193
+ if (!iconName) {
194
+ if (element) {
195
+ element.remove();
196
+ }
197
+ return null;
198
+ }
199
+
200
+ const nextElement = element || this._createIconElement(className, part);
201
+ nextElement.setAttribute("svg", iconName);
202
+
203
+ if (nextElement.parentNode !== this._surfaceElement) {
204
+ this._surfaceElement.insertBefore(nextElement, insertBeforeElement);
205
+ } else if (nextElement.nextSibling !== insertBeforeElement) {
206
+ this._surfaceElement.insertBefore(nextElement, insertBeforeElement);
207
+ }
208
+
209
+ return nextElement;
210
+ }
211
+
212
+ _syncRemoveButton() {
213
+ if (!this.hasAttribute("removable")) {
214
+ if (this._removeButton) {
215
+ this._removeButton.removeEventListener("click", this._onRemoveClick);
216
+ this._removeButton.remove();
217
+ this._removeButton = null;
218
+ }
219
+ return;
220
+ }
221
+
222
+ if (!this._removeButton) {
223
+ this._removeButton = document.createElement("button");
224
+ this._removeButton.type = "button";
225
+ this._removeButton.className = "removeButton";
226
+ this._removeButton.setAttribute("part", "remove-button");
227
+ this._removeButton.setAttribute("aria-label", "Remove tag");
228
+ this._removeButton.addEventListener("click", this._onRemoveClick);
229
+ this._surfaceElement.appendChild(this._removeButton);
230
+ }
231
+
232
+ }
233
+
234
+ _updateStructure() {
235
+ this._prefixIcon = this._syncIcon({
236
+ iconName: this.getAttribute("pre"),
237
+ element: this._prefixIcon,
238
+ className: "prefixIcon",
239
+ part: "prefix-icon",
240
+ insertBeforeElement: this._labelElement,
241
+ });
242
+
243
+ this._syncRemoveButton();
244
+
245
+ this._suffixIcon = this._syncIcon({
246
+ iconName: this.getAttribute("suf"),
247
+ element: this._suffixIcon,
248
+ className: "suffixIcon",
249
+ part: "suffix-icon",
250
+ insertBeforeElement: this._removeButton,
251
+ });
252
+ }
253
+
254
+ _onRemoveClick(event) {
255
+ event.preventDefault();
256
+ event.stopPropagation();
257
+
258
+ this.dispatchEvent(
259
+ new CustomEvent("remove-click", {
260
+ detail: {
261
+ value: this.getAttribute("value"),
262
+ },
263
+ bubbles: true,
264
+ composed: true,
265
+ }),
266
+ );
267
+ }
268
+ }
269
+
270
+ export default ({ render, html }) => {
271
+ return RettangoliTagElement;
272
+ };
@@ -0,0 +1,71 @@
1
+ import { generateCSS } from "../common.js";
2
+
3
+ const styles = {
4
+ s: {
5
+ sm: `
6
+ height: 20px;
7
+ padding-left: 8px;
8
+ padding-right: 8px;
9
+ gap: 6px;
10
+ font-size: var(--xs-font-size);
11
+ font-weight: var(--xs-font-weight);
12
+ line-height: var(--xs-line-height);
13
+ letter-spacing: var(--xs-letter-spacing);
14
+ --rtgl-tag-icon-size: 10px;
15
+ --rtgl-tag-remove-size: 14px;
16
+ `,
17
+ md: `
18
+ height: 24px;
19
+ padding-left: 10px;
20
+ padding-right: 10px;
21
+ gap: 6px;
22
+ font-size: var(--xs-font-size);
23
+ font-weight: var(--xs-font-weight);
24
+ line-height: var(--xs-line-height);
25
+ letter-spacing: var(--xs-letter-spacing);
26
+ --rtgl-tag-icon-size: 12px;
27
+ --rtgl-tag-remove-size: 16px;
28
+ `,
29
+ lg: `
30
+ height: 28px;
31
+ padding-left: 12px;
32
+ padding-right: 12px;
33
+ gap: 8px;
34
+ font-size: var(--sm-font-size);
35
+ font-weight: var(--sm-font-weight);
36
+ line-height: var(--sm-line-height);
37
+ letter-spacing: var(--sm-letter-spacing);
38
+ --rtgl-tag-icon-size: 14px;
39
+ --rtgl-tag-remove-size: 18px;
40
+ `,
41
+ },
42
+ v: {
43
+ mu: `
44
+ background-color: var(--muted);
45
+ color: var(--muted-foreground);
46
+ border-color: var(--border);
47
+ `,
48
+ pr: `
49
+ background-color: var(--primary);
50
+ color: var(--primary-foreground);
51
+ border-color: transparent;
52
+ `,
53
+ se: `
54
+ background-color: var(--secondary);
55
+ color: var(--secondary-foreground);
56
+ border-color: transparent;
57
+ `,
58
+ ac: `
59
+ background-color: var(--accent);
60
+ color: var(--accent-foreground);
61
+ border-color: transparent;
62
+ `,
63
+ de: `
64
+ background-color: var(--destructive);
65
+ color: var(--destructive-foreground);
66
+ border-color: transparent;
67
+ `,
68
+ },
69
+ };
70
+
71
+ export default generateCSS(styles, {}, ".surface");
@@ -0,0 +1,22 @@
1
+ import { generateCSS } from "../common.js";
2
+
3
+ const styles = {
4
+ c: {
5
+ pr: "color: var(--primary);",
6
+ se: "color: var(--secondary);",
7
+ de: "color: var(--destructive);",
8
+ fg: "color: var(--foreground);",
9
+ bg: "color: var(--background);",
10
+ mu: "color: var(--muted-foreground);",
11
+ ac: "color: var(--accent);",
12
+ bo: "color: var(--border);",
13
+ tr: "color: transparent;",
14
+ "pr-fg": "color: var(--primary-foreground);",
15
+ "se-fg": "color: var(--secondary-foreground);",
16
+ "de-fg": "color: var(--destructive-foreground);",
17
+ "mu-fg": "color: var(--muted-foreground);",
18
+ "ac-fg": "color: var(--accent-foreground);",
19
+ },
20
+ };
21
+
22
+ export default (targetSelector) => generateCSS(styles, {}, targetSelector);
@@ -15,6 +15,7 @@
15
15
  --border-radius-xl: 16px;
16
16
  --border-radius-f: 50%;
17
17
  --border-radius-full: 9999px;
18
+ --tag-border-radius: 9999px;
18
19
 
19
20
  --border-width-xs: 1px;
20
21
  --border-width-sm: 2px;
@@ -15,6 +15,7 @@
15
15
  --border-radius-xl: 16px;
16
16
  --border-radius-f: 50%;
17
17
  --border-radius-full: 9999px;
18
+ --tag-border-radius: 9999px;
18
19
 
19
20
  --border-width-xs: 1px;
20
21
  --border-width-sm: 2px;
@@ -15,6 +15,7 @@
15
15
  --border-radius-xl: 16px;
16
16
  --border-radius-f: 50%;
17
17
  --border-radius-full: 9999px;
18
+ --tag-border-radius: 9999px;
18
19
 
19
20
  --border-width-xs: 1px;
20
21
  --border-width-sm: 2px;