@rcarls/rc-fab 0.1.0
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/README.md +37 -0
- package/dist/custom-elements.json +238 -0
- package/dist/demo.css +85 -0
- package/dist/demo.js +40 -0
- package/dist/rc-fab-Cd1-mEO-.js +120 -0
- package/dist/rc-fab-Cd1-mEO-.js.map +1 -0
- package/dist/rc-fab-define.js +6 -0
- package/dist/rc-fab-define.js.map +1 -0
- package/dist/rc-fab.js +5 -0
- package/dist/rc-fab.js.map +1 -0
- package/dist/types/packages/rc-fab/src/define.d.ts +1 -0
- package/dist/types/packages/rc-fab/src/index.d.ts +1 -0
- package/dist/types/packages/rc-fab/src/rc-fab.d.ts +50 -0
- package/dist/types/packages/rc-fab/src/rc-fab.styles.d.ts +2 -0
- package/dist/types/packages/rc-fab/src/rc-fab.test.d.ts +0 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# `@rcarls/rc-fab`
|
|
2
|
+
|
|
3
|
+
A floating action button with regular icon-only and extended icon-and-label
|
|
4
|
+
variants. The component uses a native shadow-DOM `<button>` and provides no
|
|
5
|
+
positioning behavior; consumers own where the action floats in their layout.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @rcarls/rc-fab
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import '@rcarls/rc-fab/define';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<rc-fab label="New recipe">
|
|
21
|
+
<span slot="icon" aria-hidden="true">+</span>
|
|
22
|
+
</rc-fab>
|
|
23
|
+
|
|
24
|
+
<rc-fab variant="extended" label="New recipe">
|
|
25
|
+
<span slot="icon" aria-hidden="true">+</span>
|
|
26
|
+
</rc-fab>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`label` is required for an accessible name. It is visually hidden in the
|
|
30
|
+
regular variant and visible in the extended variant.
|
|
31
|
+
|
|
32
|
+
## Accessibility
|
|
33
|
+
|
|
34
|
+
- The inner control is a native `<button type="button">`.
|
|
35
|
+
- `disabled` maps to the native button's disabled state.
|
|
36
|
+
- Decorative icon content should use `aria-hidden="true"`.
|
|
37
|
+
- The component does not create a landmark or choose a page position.
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"readme": "",
|
|
4
|
+
"modules": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "javascript-module",
|
|
7
|
+
"path": "src/define.ts",
|
|
8
|
+
"declarations": [],
|
|
9
|
+
"exports": [
|
|
10
|
+
{
|
|
11
|
+
"kind": "custom-element-definition",
|
|
12
|
+
"name": "rc-fab",
|
|
13
|
+
"declaration": {
|
|
14
|
+
"name": "RCFab",
|
|
15
|
+
"module": "/src/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"kind": "js",
|
|
20
|
+
"name": "*",
|
|
21
|
+
"declaration": {
|
|
22
|
+
"name": "*",
|
|
23
|
+
"module": "src/index.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"kind": "javascript-module",
|
|
30
|
+
"path": "src/index.ts",
|
|
31
|
+
"declarations": [],
|
|
32
|
+
"exports": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "js",
|
|
35
|
+
"name": "*",
|
|
36
|
+
"declaration": {
|
|
37
|
+
"name": "*",
|
|
38
|
+
"module": "src/rc-fab.js"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"kind": "javascript-module",
|
|
45
|
+
"path": "src/rc-fab.ts",
|
|
46
|
+
"declarations": [
|
|
47
|
+
{
|
|
48
|
+
"kind": "class",
|
|
49
|
+
"description": "A Material Design 3 Floating Action Button.\n\nUse `variant=\"regular\"` (default) for an icon-only FAB, or\n`variant=\"extended\"` to show an icon alongside the `label`.\n\nPlace the button icon in the `icon` slot:\n```html\n<rc-fab label=\"New recipe\">\n <iconify-icon slot=\"icon\" icon=\"mdi-plus\"></iconify-icon>\n</rc-fab>\n```",
|
|
50
|
+
"name": "RCFab",
|
|
51
|
+
"cssProperties": [
|
|
52
|
+
{
|
|
53
|
+
"description": "Button background colour.",
|
|
54
|
+
"name": "--rc-fab-bg",
|
|
55
|
+
"default": "Canvas"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Hover background colour.",
|
|
59
|
+
"name": "--rc-fab-bg-hover",
|
|
60
|
+
"default": "var(--rc-fab-bg)"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "Foreground (icon + label) colour.",
|
|
64
|
+
"name": "--rc-fab-color",
|
|
65
|
+
"default": "CanvasText"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"description": "Height and minimum width of the button.",
|
|
69
|
+
"name": "--rc-fab-size",
|
|
70
|
+
"default": "3.5rem"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Border-radius of the button.",
|
|
74
|
+
"name": "--rc-fab-radius",
|
|
75
|
+
"default": "1rem"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Box shadow at rest.",
|
|
79
|
+
"name": "--rc-fab-shadow"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"description": "Box shadow on hover.",
|
|
83
|
+
"name": "--rc-fab-shadow-hover"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"description": "Box shadow while pressed.",
|
|
87
|
+
"name": "--rc-fab-shadow-active"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"description": "Inline padding (extended variant).",
|
|
91
|
+
"name": "--rc-fab-padding-inline",
|
|
92
|
+
"default": "1rem"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"description": "Gap between icon and label (extended variant).",
|
|
96
|
+
"name": "--rc-fab-gap",
|
|
97
|
+
"default": "0.5rem"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"description": "Font-size applied to the slotted icon.",
|
|
101
|
+
"name": "--rc-fab-icon-size",
|
|
102
|
+
"default": "1.5rem"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"description": "Label font size (extended variant).",
|
|
106
|
+
"name": "--rc-fab-font-size",
|
|
107
|
+
"default": "0.875rem"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"description": "Label font weight.",
|
|
111
|
+
"name": "--rc-fab-font-weight",
|
|
112
|
+
"default": "500"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"description": "Label letter spacing.",
|
|
116
|
+
"name": "--rc-fab-letter-spacing",
|
|
117
|
+
"default": "0.00625em"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"description": "Focus ring style.",
|
|
121
|
+
"name": "--rc-fab-focus-ring",
|
|
122
|
+
"default": "2px solid currentColor"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"description": "Focus ring offset.",
|
|
126
|
+
"name": "--rc-fab-focus-ring-offset",
|
|
127
|
+
"default": "2px"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"description": "Transition speed for hover/active.",
|
|
131
|
+
"name": "--rc-fab-transition-duration",
|
|
132
|
+
"default": "200ms"
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"cssParts": [
|
|
136
|
+
{
|
|
137
|
+
"description": "The inner `<button>` element.",
|
|
138
|
+
"name": "button"
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"slots": [
|
|
142
|
+
{
|
|
143
|
+
"description": "The icon element displayed inside the button.",
|
|
144
|
+
"name": "icon"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"members": [
|
|
148
|
+
{
|
|
149
|
+
"kind": "field",
|
|
150
|
+
"name": "variant",
|
|
151
|
+
"type": {
|
|
152
|
+
"text": "'regular' | 'extended'"
|
|
153
|
+
},
|
|
154
|
+
"default": "'regular'",
|
|
155
|
+
"description": "Display variant. `regular` shows only the icon; `extended` adds the label.",
|
|
156
|
+
"attribute": "variant",
|
|
157
|
+
"reflects": true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"kind": "field",
|
|
161
|
+
"name": "label",
|
|
162
|
+
"type": {
|
|
163
|
+
"text": "string"
|
|
164
|
+
},
|
|
165
|
+
"default": "''",
|
|
166
|
+
"description": "Visible label text shown in the `extended` variant and used as `aria-label` for `regular`.",
|
|
167
|
+
"attribute": "label"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"kind": "field",
|
|
171
|
+
"name": "disabled",
|
|
172
|
+
"type": {
|
|
173
|
+
"text": "boolean"
|
|
174
|
+
},
|
|
175
|
+
"default": "false",
|
|
176
|
+
"description": "Disables the button.",
|
|
177
|
+
"attribute": "disabled",
|
|
178
|
+
"reflects": true
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
"attributes": [
|
|
182
|
+
{
|
|
183
|
+
"name": "variant",
|
|
184
|
+
"type": {
|
|
185
|
+
"text": "'regular' | 'extended'"
|
|
186
|
+
},
|
|
187
|
+
"default": "'regular'",
|
|
188
|
+
"description": "Display variant. `regular` shows only the icon; `extended` adds the label.",
|
|
189
|
+
"fieldName": "variant"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"name": "label",
|
|
193
|
+
"type": {
|
|
194
|
+
"text": "string"
|
|
195
|
+
},
|
|
196
|
+
"default": "''",
|
|
197
|
+
"description": "Visible label text shown in the `extended` variant and used as `aria-label` for `regular`.",
|
|
198
|
+
"fieldName": "label"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"name": "disabled",
|
|
202
|
+
"type": {
|
|
203
|
+
"text": "boolean"
|
|
204
|
+
},
|
|
205
|
+
"default": "false",
|
|
206
|
+
"description": "Disables the button.",
|
|
207
|
+
"fieldName": "disabled"
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"superclass": {
|
|
211
|
+
"name": "LitElement",
|
|
212
|
+
"package": "lit"
|
|
213
|
+
},
|
|
214
|
+
"tagName": "rc-fab",
|
|
215
|
+
"customElement": true
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"exports": [
|
|
219
|
+
{
|
|
220
|
+
"kind": "js",
|
|
221
|
+
"name": "RCFab",
|
|
222
|
+
"declaration": {
|
|
223
|
+
"name": "RCFab",
|
|
224
|
+
"module": "src/rc-fab.ts"
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"kind": "js",
|
|
229
|
+
"name": "default",
|
|
230
|
+
"declaration": {
|
|
231
|
+
"name": "RCFab",
|
|
232
|
+
"module": "src/rc-fab.ts"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
}
|
package/dist/demo.css
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
*, *::before, *::after {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
--rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@supports (color: AccentColor) {
|
|
11
|
+
:root {
|
|
12
|
+
--rc-accent: AccentColor;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[data-theme="light"] { color-scheme: light; }
|
|
17
|
+
[data-theme="dark"] { color-scheme: dark; }
|
|
18
|
+
|
|
19
|
+
[data-theme="solarized-light"] {
|
|
20
|
+
color-scheme: light;
|
|
21
|
+
--rc-surface: #fdf6e3;
|
|
22
|
+
--rc-text: #657b83;
|
|
23
|
+
--rc-border: 1px solid #93a1a1;
|
|
24
|
+
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
[data-theme="solarized-dark"] {
|
|
28
|
+
color-scheme: dark;
|
|
29
|
+
--rc-surface: #002b36;
|
|
30
|
+
--rc-text: #839496;
|
|
31
|
+
--rc-border: 1px solid #586e75;
|
|
32
|
+
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: system-ui, sans-serif;
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.demo-page {
|
|
41
|
+
max-width: 60rem;
|
|
42
|
+
margin: 0 auto;
|
|
43
|
+
padding: 2rem 1.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.demo-controls {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 1rem;
|
|
50
|
+
margin-bottom: 2rem;
|
|
51
|
+
padding-bottom: 1rem;
|
|
52
|
+
border-bottom: 1px solid ButtonBorder;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.demo-controls .demo-title {
|
|
56
|
+
flex: 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.demo-controls h1 {
|
|
60
|
+
margin: 0 0 0.15rem;
|
|
61
|
+
font-size: 1.5rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.demo-controls a {
|
|
65
|
+
font-size: 0.8rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.demo-section {
|
|
69
|
+
margin-bottom: 2rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.demo-section h2 {
|
|
73
|
+
margin: 0 0 0.5rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.theme-picker {
|
|
77
|
+
padding: 0.35em 0.75em;
|
|
78
|
+
font-family: inherit;
|
|
79
|
+
font-size: 0.8rem;
|
|
80
|
+
cursor: pointer;
|
|
81
|
+
border: 1px solid ButtonBorder;
|
|
82
|
+
border-radius: 4px;
|
|
83
|
+
background: Canvas;
|
|
84
|
+
color: CanvasText;
|
|
85
|
+
}
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
|
|
2
|
+
const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
|
|
3
|
+
|
|
4
|
+
const stored = localStorage.getItem('rc-demo-theme') ?? '';
|
|
5
|
+
applyTheme(stored);
|
|
6
|
+
|
|
7
|
+
function applyTheme(theme) {
|
|
8
|
+
if (theme) {
|
|
9
|
+
document.documentElement.dataset.theme = theme;
|
|
10
|
+
} else {
|
|
11
|
+
delete document.documentElement.dataset.theme;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function currentIndex() {
|
|
16
|
+
const current = document.documentElement.dataset.theme ?? '';
|
|
17
|
+
const idx = THEMES.indexOf(current);
|
|
18
|
+
return idx === -1 ? 0 : idx;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function updateButtons() {
|
|
22
|
+
const label = LABELS[currentIndex()];
|
|
23
|
+
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
24
|
+
btn.textContent = label;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
window.cycleTheme = function () {
|
|
29
|
+
const next = THEMES[(currentIndex() + 1) % THEMES.length];
|
|
30
|
+
applyTheme(next);
|
|
31
|
+
localStorage.setItem('rc-demo-theme', next);
|
|
32
|
+
updateButtons();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
36
|
+
updateButtons();
|
|
37
|
+
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
38
|
+
btn.addEventListener('click', window.cycleTheme);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { css as d, LitElement as c, html as f } from "lit";
|
|
2
|
+
import { property as t } from "lit/decorators.js";
|
|
3
|
+
const p = d`
|
|
4
|
+
:host {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:host([hidden]) {
|
|
9
|
+
display: none;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
button {
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
gap: var(--rc-fab-gap, 0.5rem);
|
|
17
|
+
|
|
18
|
+
min-width: var(--rc-fab-size, 3.5rem);
|
|
19
|
+
height: var(--rc-fab-size, 3.5rem);
|
|
20
|
+
padding-block: 0;
|
|
21
|
+
padding-inline: var(--rc-fab-padding-inline, 1rem);
|
|
22
|
+
|
|
23
|
+
background: var(--rc-fab-bg, Canvas);
|
|
24
|
+
color: var(--rc-fab-color, CanvasText);
|
|
25
|
+
|
|
26
|
+
border: none;
|
|
27
|
+
border-radius: var(--rc-fab-radius, 1rem);
|
|
28
|
+
box-shadow: var(--rc-fab-shadow, 0 3px 8px rgb(0 0 0 / 0.3));
|
|
29
|
+
|
|
30
|
+
font-family: var(--rc-fab-font-family, inherit);
|
|
31
|
+
font-size: var(--rc-fab-font-size, 0.875rem);
|
|
32
|
+
font-weight: var(--rc-fab-font-weight, 500);
|
|
33
|
+
letter-spacing: var(--rc-fab-letter-spacing, 0.00625em);
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition:
|
|
38
|
+
background var(--rc-fab-transition-duration, 200ms) ease,
|
|
39
|
+
box-shadow var(--rc-fab-transition-duration, 200ms) ease,
|
|
40
|
+
transform var(--rc-fab-transition-duration, 200ms) ease;
|
|
41
|
+
|
|
42
|
+
&:hover {
|
|
43
|
+
background: var(--rc-fab-bg-hover, var(--rc-fab-bg, Canvas));
|
|
44
|
+
box-shadow: var(--rc-fab-shadow-hover, 0 6px 16px rgb(0 0 0 / 0.3));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&:active {
|
|
48
|
+
box-shadow: var(--rc-fab-shadow-active, 0 2px 4px rgb(0 0 0 / 0.3));
|
|
49
|
+
transform: scale(0.96);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:focus-visible {
|
|
53
|
+
outline: var(--rc-fab-focus-ring, 2px solid currentColor);
|
|
54
|
+
outline-offset: var(--rc-fab-focus-ring-offset, 2px);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&:disabled {
|
|
58
|
+
opacity: 0.38;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
box-shadow: none;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Regular variant: icon-only, square-ish with equal padding */
|
|
65
|
+
:host([variant='regular']) button {
|
|
66
|
+
padding-inline: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#label {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Extended variant: icon + label */
|
|
74
|
+
:host([variant='extended']) #label {
|
|
75
|
+
display: inline;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
slot[name='icon']::slotted(*) {
|
|
79
|
+
font-size: var(--rc-fab-icon-size, 1.5rem);
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
var v = Object.defineProperty, n = (o, s, l, h) => {
|
|
84
|
+
for (var a = void 0, e = o.length - 1, b; e >= 0; e--)
|
|
85
|
+
(b = o[e]) && (a = b(s, l, a) || a);
|
|
86
|
+
return a && v(s, l, a), a;
|
|
87
|
+
};
|
|
88
|
+
const i = class i extends c {
|
|
89
|
+
constructor() {
|
|
90
|
+
super(...arguments), this.variant = "regular", this.label = "", this.disabled = !1;
|
|
91
|
+
}
|
|
92
|
+
render() {
|
|
93
|
+
return f`
|
|
94
|
+
<button
|
|
95
|
+
part="button"
|
|
96
|
+
type="button"
|
|
97
|
+
?disabled=${this.disabled}
|
|
98
|
+
aria-label=${this.variant === "regular" ? this.label : ""}
|
|
99
|
+
>
|
|
100
|
+
<slot name="icon"></slot>
|
|
101
|
+
<span id="label">${this.label}</span>
|
|
102
|
+
</button>
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
i.styles = p;
|
|
107
|
+
let r = i;
|
|
108
|
+
n([
|
|
109
|
+
t({ type: String, reflect: !0 })
|
|
110
|
+
], r.prototype, "variant");
|
|
111
|
+
n([
|
|
112
|
+
t({ type: String })
|
|
113
|
+
], r.prototype, "label");
|
|
114
|
+
n([
|
|
115
|
+
t({ type: Boolean, reflect: !0 })
|
|
116
|
+
], r.prototype, "disabled");
|
|
117
|
+
export {
|
|
118
|
+
r as R
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=rc-fab-Cd1-mEO-.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-fab-Cd1-mEO-.js","sources":["../src/rc-fab.styles.ts","../src/rc-fab.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const fabStyles = css`\n :host {\n display: inline-flex;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--rc-fab-gap, 0.5rem);\n\n min-width: var(--rc-fab-size, 3.5rem);\n height: var(--rc-fab-size, 3.5rem);\n padding-block: 0;\n padding-inline: var(--rc-fab-padding-inline, 1rem);\n\n background: var(--rc-fab-bg, Canvas);\n color: var(--rc-fab-color, CanvasText);\n\n border: none;\n border-radius: var(--rc-fab-radius, 1rem);\n box-shadow: var(--rc-fab-shadow, 0 3px 8px rgb(0 0 0 / 0.3));\n\n font-family: var(--rc-fab-font-family, inherit);\n font-size: var(--rc-fab-font-size, 0.875rem);\n font-weight: var(--rc-fab-font-weight, 500);\n letter-spacing: var(--rc-fab-letter-spacing, 0.00625em);\n white-space: nowrap;\n\n cursor: pointer;\n transition:\n background var(--rc-fab-transition-duration, 200ms) ease,\n box-shadow var(--rc-fab-transition-duration, 200ms) ease,\n transform var(--rc-fab-transition-duration, 200ms) ease;\n\n &:hover {\n background: var(--rc-fab-bg-hover, var(--rc-fab-bg, Canvas));\n box-shadow: var(--rc-fab-shadow-hover, 0 6px 16px rgb(0 0 0 / 0.3));\n }\n\n &:active {\n box-shadow: var(--rc-fab-shadow-active, 0 2px 4px rgb(0 0 0 / 0.3));\n transform: scale(0.96);\n }\n\n &:focus-visible {\n outline: var(--rc-fab-focus-ring, 2px solid currentColor);\n outline-offset: var(--rc-fab-focus-ring-offset, 2px);\n }\n\n &:disabled {\n opacity: 0.38;\n pointer-events: none;\n box-shadow: none;\n }\n }\n\n /* Regular variant: icon-only, square-ish with equal padding */\n :host([variant='regular']) button {\n padding-inline: 0;\n }\n\n #label {\n display: none;\n }\n\n /* Extended variant: icon + label */\n :host([variant='extended']) #label {\n display: inline;\n }\n\n slot[name='icon']::slotted(*) {\n font-size: var(--rc-fab-icon-size, 1.5rem);\n flex-shrink: 0;\n }\n`;\n\nexport default fabStyles;\n","import { LitElement, html } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport fabStyles from './rc-fab.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-fab': RCFab;\n }\n}\n\n/**\n * A Material Design 3 Floating Action Button.\n *\n * Use `variant=\"regular\"` (default) for an icon-only FAB, or\n * `variant=\"extended\"` to show an icon alongside the `label`.\n *\n * Place the button icon in the `icon` slot:\n * ```html\n * <rc-fab label=\"New recipe\">\n * <iconify-icon slot=\"icon\" icon=\"mdi-plus\"></iconify-icon>\n * </rc-fab>\n * ```\n *\n * @slot icon - The icon element displayed inside the button.\n * @csspart button - The inner `<button>` element.\n * @cssprop [--rc-fab-bg=Canvas] - Button background colour.\n * @cssprop [--rc-fab-bg-hover=var(--rc-fab-bg)] - Hover background colour.\n * @cssprop [--rc-fab-color=CanvasText] - Foreground (icon + label) colour.\n * @cssprop [--rc-fab-size=3.5rem] - Height and minimum width of the button.\n * @cssprop [--rc-fab-radius=1rem] - Border-radius of the button.\n * @cssprop [--rc-fab-shadow] - Box shadow at rest.\n * @cssprop [--rc-fab-shadow-hover] - Box shadow on hover.\n * @cssprop [--rc-fab-shadow-active] - Box shadow while pressed.\n * @cssprop [--rc-fab-padding-inline=1rem] - Inline padding (extended variant).\n * @cssprop [--rc-fab-gap=0.5rem] - Gap between icon and label (extended variant).\n * @cssprop [--rc-fab-icon-size=1.5rem] - Font-size applied to the slotted icon.\n * @cssprop [--rc-fab-font-size=0.875rem] - Label font size (extended variant).\n * @cssprop [--rc-fab-font-weight=500] - Label font weight.\n * @cssprop [--rc-fab-letter-spacing=0.00625em] - Label letter spacing.\n * @cssprop [--rc-fab-focus-ring=2px solid currentColor] - Focus ring style.\n * @cssprop [--rc-fab-focus-ring-offset=2px] - Focus ring offset.\n * @cssprop [--rc-fab-transition-duration=200ms] - Transition speed for hover/active.\n */\nexport class RCFab extends LitElement {\n static override styles = fabStyles;\n\n /** Display variant. `regular` shows only the icon; `extended` adds the label. */\n @property({ type: String, reflect: true })\n variant: 'regular' | 'extended' = 'regular';\n\n /** Visible label text shown in the `extended` variant and used as `aria-label` for `regular`. */\n @property({ type: String })\n label = '';\n\n /** Disables the button. */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n protected override render() {\n return html`\n <button\n part=\"button\"\n type=\"button\"\n ?disabled=${this.disabled}\n aria-label=${this.variant === 'regular' ? this.label : ''}\n >\n <slot name=\"icon\"></slot>\n <span id=\"label\">${this.label}</span>\n </button>\n `;\n }\n}\n\nexport default RCFab;\n"],"names":["fabStyles","css","_RCFab","LitElement","html","RCFab","__decorateClass","property"],"mappings":";;AAEO,MAAMA,IAAYC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;AC0ClB,MAAMC,IAAN,MAAMA,UAAcC,EAAW;AAAA,EAA/B,cAAA;AAAA,UAAA,GAAA,SAAA,GAKL,KAAA,UAAkC,WAIlC,KAAA,QAAQ,IAIR,KAAA,WAAW;AAAA,EAAA;AAAA,EAEQ,SAAS;AAC1B,WAAOC;AAAA;AAAA;AAAA;AAAA,oBAIS,KAAK,QAAQ;AAAA,qBACZ,KAAK,YAAY,YAAY,KAAK,QAAQ,EAAE;AAAA;AAAA;AAAA,2BAGtC,KAAK,KAAK;AAAA;AAAA;AAAA,EAGnC;AACF;AA3BEF,EAAgB,SAASF;AADpB,IAAMK,IAANH;AAKLI,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAJ9BF,EAKX,WAAA,SAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfF,EASX,WAAA,OAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAZ/BF,EAaX,WAAA,UAAA;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-fab-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCFab } from './index.js';\n\ncustomElements.get('rc-fab') || customElements.define('rc-fab', RCFab);\n\nexport * from './index.js';\n"],"names":["RCFab"],"mappings":";AAEA,eAAe,IAAI,QAAQ,KAAK,eAAe,OAAO,UAAUA,CAAK;"}
|
package/dist/rc-fab.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-fab.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rc-fab.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
declare global {
|
|
3
|
+
interface HTMLElementTagNameMap {
|
|
4
|
+
'rc-fab': RCFab;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A Material Design 3 Floating Action Button.
|
|
9
|
+
*
|
|
10
|
+
* Use `variant="regular"` (default) for an icon-only FAB, or
|
|
11
|
+
* `variant="extended"` to show an icon alongside the `label`.
|
|
12
|
+
*
|
|
13
|
+
* Place the button icon in the `icon` slot:
|
|
14
|
+
* ```html
|
|
15
|
+
* <rc-fab label="New recipe">
|
|
16
|
+
* <iconify-icon slot="icon" icon="mdi-plus"></iconify-icon>
|
|
17
|
+
* </rc-fab>
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @slot icon - The icon element displayed inside the button.
|
|
21
|
+
* @csspart button - The inner `<button>` element.
|
|
22
|
+
* @cssprop [--rc-fab-bg=Canvas] - Button background colour.
|
|
23
|
+
* @cssprop [--rc-fab-bg-hover=var(--rc-fab-bg)] - Hover background colour.
|
|
24
|
+
* @cssprop [--rc-fab-color=CanvasText] - Foreground (icon + label) colour.
|
|
25
|
+
* @cssprop [--rc-fab-size=3.5rem] - Height and minimum width of the button.
|
|
26
|
+
* @cssprop [--rc-fab-radius=1rem] - Border-radius of the button.
|
|
27
|
+
* @cssprop [--rc-fab-shadow] - Box shadow at rest.
|
|
28
|
+
* @cssprop [--rc-fab-shadow-hover] - Box shadow on hover.
|
|
29
|
+
* @cssprop [--rc-fab-shadow-active] - Box shadow while pressed.
|
|
30
|
+
* @cssprop [--rc-fab-padding-inline=1rem] - Inline padding (extended variant).
|
|
31
|
+
* @cssprop [--rc-fab-gap=0.5rem] - Gap between icon and label (extended variant).
|
|
32
|
+
* @cssprop [--rc-fab-icon-size=1.5rem] - Font-size applied to the slotted icon.
|
|
33
|
+
* @cssprop [--rc-fab-font-size=0.875rem] - Label font size (extended variant).
|
|
34
|
+
* @cssprop [--rc-fab-font-weight=500] - Label font weight.
|
|
35
|
+
* @cssprop [--rc-fab-letter-spacing=0.00625em] - Label letter spacing.
|
|
36
|
+
* @cssprop [--rc-fab-focus-ring=2px solid currentColor] - Focus ring style.
|
|
37
|
+
* @cssprop [--rc-fab-focus-ring-offset=2px] - Focus ring offset.
|
|
38
|
+
* @cssprop [--rc-fab-transition-duration=200ms] - Transition speed for hover/active.
|
|
39
|
+
*/
|
|
40
|
+
export declare class RCFab extends LitElement {
|
|
41
|
+
static styles: import('lit').CSSResult;
|
|
42
|
+
/** Display variant. `regular` shows only the icon; `extended` adds the label. */
|
|
43
|
+
variant: 'regular' | 'extended';
|
|
44
|
+
/** Visible label text shown in the `extended` variant and used as `aria-label` for `regular`. */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Disables the button. */
|
|
47
|
+
disabled: boolean;
|
|
48
|
+
protected render(): import('lit').TemplateResult<1>;
|
|
49
|
+
}
|
|
50
|
+
export default RCFab;
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcarls/rc-fab",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"description": "Headless floating action button web component built with Lit",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
|
+
"directory": "packages/rc-fab"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/richardcarls/rc-webcomponents#readme",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"module": "./dist/rc-fab.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/types/packages/rc-fab/src/index.d.ts",
|
|
24
|
+
"default": "./dist/rc-fab.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./define": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/types/packages/rc-fab/src/define.d.ts",
|
|
30
|
+
"default": "./dist/rc-fab-define.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"types": "./dist/types/packages/rc-fab/src/index.d.ts",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./dist/rc-fab-define.js"
|
|
37
|
+
],
|
|
38
|
+
"customElements": "dist/custom-elements.json",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "vite",
|
|
41
|
+
"build": "tsc && vite build && cem analyze",
|
|
42
|
+
"cem:analyze": "cem analyze",
|
|
43
|
+
"preview": "vite preview",
|
|
44
|
+
"test:browser": "vitest",
|
|
45
|
+
"test:browser:chrome": "vitest --project=chromium",
|
|
46
|
+
"test:browser:firefox": "vitest --project=firefox",
|
|
47
|
+
"yalc:publish": "yalc publish --push"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
51
|
+
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
52
|
+
"@vitest/browser-playwright": "4.1.5",
|
|
53
|
+
"lit": "^3.0.0",
|
|
54
|
+
"playwright": "^1.56.0",
|
|
55
|
+
"rollup": "^4.60.2",
|
|
56
|
+
"typescript": "~5.9.3",
|
|
57
|
+
"vite": "^7.1.7",
|
|
58
|
+
"vite-plugin-dts": "^4.5.4",
|
|
59
|
+
"vitest": "^4.0.6",
|
|
60
|
+
"vitest-browser-lit": "^1.0.1"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"lit": "^3.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|