@timmo001/groundwork-ui 0.7.0 → 0.8.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/custom-elements.json +50 -6
- package/package.json +1 -1
- package/src/gw-button.ts +26 -2
- package/src/gw-chip.ts +20 -1
- package/src/layout.ts +6 -3
- package/src/styles.ts +1 -0
package/custom-elements.json
CHANGED
|
@@ -3103,7 +3103,7 @@
|
|
|
3103
3103
|
"text": "Properties"
|
|
3104
3104
|
},
|
|
3105
3105
|
"static": true,
|
|
3106
|
-
"default": "{ variant: { reflect: true }, appearance: { reflect: true }, size: { reflect: true }, type: {}, href: {}, label: {}, disabled: { type: \"boolean\", reflect: true }, loading: { type: \"boolean\", reflect: true }, icon: {}, labels: { reflect: true }, }",
|
|
3106
|
+
"default": "{ variant: { reflect: true }, appearance: { reflect: true }, size: { reflect: true }, type: {}, href: {}, label: {}, disabled: { type: \"boolean\", reflect: true }, loading: { type: \"boolean\", reflect: true }, icon: {}, swatch: {}, labels: { reflect: true }, }",
|
|
3107
3107
|
"inheritedFrom": {
|
|
3108
3108
|
"name": "GwElement",
|
|
3109
3109
|
"module": "src/element.ts"
|
|
@@ -3130,7 +3130,7 @@
|
|
|
3130
3130
|
"text": "readonly CSSStyleSheet[]"
|
|
3131
3131
|
},
|
|
3132
3132
|
"static": true,
|
|
3133
|
-
"default": "[ base, controlSizes(\"button\"), css` :host { --gw-button-tone: var(--gw-color-accent); display: inline-block; } :host([variant=\"neutral\"]) { --gw-button-tone: var(--gw-color-text-secondary); --gw-button-ink: var(--gw-color-text-strong); } :host([variant=\"info\"]) { --gw-button-tone: var(--gw-color-info); } :host([variant=\"success\"]) { --gw-button-tone: var(--gw-color-success); } :host([variant=\"warning\"]) { --gw-button-tone: var(--gw-color-warning); } :host([variant=\"danger\"]) { --gw-button-tone: var(--gw-color-danger); } .button { --gw-size: var(--gw-button-scale, 1); --gw-scale: calc(var(--gw-size) * var(--gw-control-scale, 1)); --gw-icon-size: calc(1.125rem * var(--gw-scale)); position: relative; display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-size)); align-items: center; justify-content: center; min-height: calc(2.5rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-4) * var(--gw-size)); font: inherit; font-size: calc(var(--gw-font-size-s) * var(--gw-size)); font-weight: var(--gw-font-weight-strong); line-height: 1; color: var(--gw-button-ink, var(--gw-button-tone)); text-decoration: none; text-transform: var(--gw-label-transform); letter-spacing: var(--gw-label-tracking); white-space: nowrap; cursor: pointer; background: transparent; border: max(var(--gw-border-width), 1px) solid transparent; border-radius: var(--gw-radius-pill); transition: background-color var(--gw-motion-fast) var(--gw-motion-easing), border-color var(--gw-motion-fast) var(--gw-motion-easing), color var(--gw-motion-fast) var(--gw-motion-easing), scale var(--gw-motion-fast) var(--gw-motion-easing); } /* A slight press, so a click feels physical */ .button:active { scale: 0.97; } .button:hover { background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } .button:active { background: color-mix(in oklch, var(--gw-button-tone) 24%, transparent); } /* A solid fill, with text that flips between black and white by the fill's lightness so it reads on every theme's colors */ :host([appearance=\"accent\"]) .button { color: oklch( from var(--gw-button-tone) clamp(0, (0.66 - l) * 1000, 1) 0 0 ); background: var(--gw-button-tone); } :host([appearance=\"accent\"]) .button:hover { background: oklch( from var(--gw-button-tone) calc(l + (0.6 - l) * 0.2) c h ); } :host([appearance=\"accent\"]) .button:active { background: oklch( from var(--gw-button-tone) calc(l + (0.6 - l) * 0.35) c h ); } /* The tint lowers the tone's contrast, so the text leans toward the strongest text color to stay readable on it */ :host([appearance=\"filled\"]) .button { color: var( --gw-button-ink, color-mix( in oklch, var(--gw-button-tone) 70%, var(--gw-color-text-strong) ) ); background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } :host([appearance=\"filled\"]) .button:hover { background: color-mix(in oklch, var(--gw-button-tone) 24%, transparent); } :host([appearance=\"filled\"]) .button:active { background: color-mix(in oklch, var(--gw-button-tone) 32%, transparent); } :host([appearance=\"outlined\"]) .button { border-color: var(--gw-button-tone); } /* A slotted link carries the text; the pill draws its focus ring */ ::slotted(a) { color: inherit; text-decoration: none; outline: none; } .button.focused { outline: var(--gw-focus-width) solid var(--gw-color-focus); outline-offset: var(--gw-focus-offset); } :host([appearance=\"plain\"]) .button.current, :host([appearance=\"outlined\"]) .button.current { background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } :host([appearance=\"filled\"]) .button.current { background: color-mix(in oklch, var(--gw-button-tone) 32%, transparent); } .button:disabled, .button[aria-disabled=\"true\"] { color: var(--gw-color-text-disabled); pointer-events: none; cursor: not-allowed; background: var(--gw-color-fill-neutral-disabled); border-color: transparent; } :host([appearance=\"plain\"]) .button:disabled, :host([appearance=\"plain\"]) .button[aria-disabled=\"true\"] { background: transparent; } ::slotted([slot=\"icon\"]), .icon { flex: none; width: var(--gw-icon-size); height: var(--gw-icon-size); fill: currentColor; } /* The icon and the ring share one cell and crossfade */ .lead { display: grid; place-items: center; } .lead >
|
|
3133
|
+
"default": "[ base, controlSizes(\"button\"), css` :host { --gw-button-tone: var(--gw-color-accent); display: inline-block; } :host([variant=\"neutral\"]) { --gw-button-tone: var(--gw-color-text-secondary); --gw-button-ink: var(--gw-color-text-strong); } :host([variant=\"info\"]) { --gw-button-tone: var(--gw-color-info); } :host([variant=\"success\"]) { --gw-button-tone: var(--gw-color-success); } :host([variant=\"warning\"]) { --gw-button-tone: var(--gw-color-warning); } :host([variant=\"danger\"]) { --gw-button-tone: var(--gw-color-danger); } .button { --gw-size: var(--gw-button-scale, 1); --gw-scale: calc(var(--gw-size) * var(--gw-control-scale, 1)); --gw-icon-size: calc(1.125rem * var(--gw-scale)); position: relative; display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-size)); align-items: center; justify-content: center; min-height: calc(2.5rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-4) * var(--gw-size)); font: inherit; font-size: calc(var(--gw-font-size-s) * var(--gw-size)); font-weight: var(--gw-font-weight-strong); line-height: 1; color: var(--gw-button-ink, var(--gw-button-tone)); text-decoration: none; text-transform: var(--gw-label-transform); letter-spacing: var(--gw-label-tracking); white-space: nowrap; cursor: pointer; background: transparent; border: max(var(--gw-border-width), 1px) solid transparent; border-radius: var(--gw-radius-pill); transition: background-color var(--gw-motion-fast) var(--gw-motion-easing), border-color var(--gw-motion-fast) var(--gw-motion-easing), color var(--gw-motion-fast) var(--gw-motion-easing), scale var(--gw-motion-fast) var(--gw-motion-easing); } /* A slight press, so a click feels physical */ .button:active { scale: 0.97; } .button:hover { background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } .button:active { background: color-mix(in oklch, var(--gw-button-tone) 24%, transparent); } /* A solid fill, with text that flips between black and white by the fill's lightness so it reads on every theme's colors */ :host([appearance=\"accent\"]) .button { color: oklch( from var(--gw-button-tone) clamp(0, (0.66 - l) * 1000, 1) 0 0 ); background: var(--gw-button-tone); } :host([appearance=\"accent\"]) .button:hover { background: oklch( from var(--gw-button-tone) calc(l + (0.6 - l) * 0.2) c h ); } :host([appearance=\"accent\"]) .button:active { background: oklch( from var(--gw-button-tone) calc(l + (0.6 - l) * 0.35) c h ); } /* The tint lowers the tone's contrast, so the text leans toward the strongest text color to stay readable on it */ :host([appearance=\"filled\"]) .button { color: var( --gw-button-ink, color-mix( in oklch, var(--gw-button-tone) 70%, var(--gw-color-text-strong) ) ); background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } :host([appearance=\"filled\"]) .button:hover { background: color-mix(in oklch, var(--gw-button-tone) 24%, transparent); } :host([appearance=\"filled\"]) .button:active { background: color-mix(in oklch, var(--gw-button-tone) 32%, transparent); } :host([appearance=\"outlined\"]) .button { border-color: var(--gw-button-tone); } /* A slotted link carries the text; the pill draws its focus ring */ ::slotted(a) { color: inherit; text-decoration: none; outline: none; } .button.focused { outline: var(--gw-focus-width) solid var(--gw-color-focus); outline-offset: var(--gw-focus-offset); } :host([appearance=\"plain\"]) .button.current, :host([appearance=\"outlined\"]) .button.current { background: color-mix(in oklch, var(--gw-button-tone) 16%, transparent); } :host([appearance=\"filled\"]) .button.current { background: color-mix(in oklch, var(--gw-button-tone) 32%, transparent); } .button:disabled, .button[aria-disabled=\"true\"] { color: var(--gw-color-text-disabled); pointer-events: none; cursor: not-allowed; background: var(--gw-color-fill-neutral-disabled); border-color: transparent; } :host([appearance=\"plain\"]) .button:disabled, :host([appearance=\"plain\"]) .button[aria-disabled=\"true\"] { background: transparent; } ::slotted([slot=\"icon\"]), .icon { flex: none; width: var(--gw-icon-size); height: var(--gw-icon-size); fill: currentColor; } /* The icon and the ring share one cell and crossfade */ .lead { display: grid; place-items: center; } /* The icon slot is display: contents, so its slotted icon is a grid item of its own and needs the shared cell too */ .lead > *, ::slotted([slot=\"icon\"]) { grid-area: 1 / 1; } /* A color dot in the icon's place */ .swatch { width: calc(var(--gw-icon-size) * 0.6); height: calc(var(--gw-icon-size) * 0.6); border: 1px solid color-mix(in oklab, var(--gw-color-text-primary) 20%, transparent); border-radius: 50%; } .lead > *, .text, .ring { transition: opacity var(--gw-motion-normal) cubic-bezier(0.4, 0, 0.2, 1); } /* Sized to the icon's drawn area, which is inset in its 24px box */ .ring { width: calc(var(--gw-icon-size) * 0.8); height: calc(var(--gw-icon-size) * 0.8); border: calc(2px * var(--gw-scale)) solid color-mix(in oklch, currentColor 25%, transparent); border-top-color: currentColor; border-radius: 50%; opacity: 0; animation: spin 0.9s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Without an icon, the ring sits over the hidden text */ .ring.over { position: absolute; inset: 0; margin: auto; } :host([loading]) .button { cursor: progress; } :host([loading]) .lead > .ring, :host([loading]) .button:not(.has-icon) > .ring.over { opacity: 1; } :host([loading]) .lead > :not(.ring), :host([loading]) .button:not(.has-icon) > .text { opacity: 0; } .button:not(.has-icon) > .lead { display: none; } /* Icon only, to save space: square, with the text kept for assistive technology. auto does this on narrow screens */ :host([labels=\"hide\"]) .button.has-icon { min-width: calc(2.5rem * var(--gw-scale)); padding: 0; } :host([labels=\"hide\"]) .has-icon .text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } @media (width < 40rem) { :host([labels=\"auto\"]) .button.has-icon { min-width: calc(2.5rem * var(--gw-scale)); padding: 0; } :host([labels=\"auto\"]) .has-icon .text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } } `, ]",
|
|
3134
3134
|
"inheritedFrom": {
|
|
3135
3135
|
"name": "GwElement",
|
|
3136
3136
|
"module": "src/element.ts"
|
|
@@ -3210,6 +3210,15 @@
|
|
|
3210
3210
|
"description": "SVG path data for an icon before the text.",
|
|
3211
3211
|
"default": "\"\""
|
|
3212
3212
|
},
|
|
3213
|
+
{
|
|
3214
|
+
"kind": "field",
|
|
3215
|
+
"name": "swatch",
|
|
3216
|
+
"type": {
|
|
3217
|
+
"text": "string"
|
|
3218
|
+
},
|
|
3219
|
+
"description": "A CSS color, drawn as a small round dot in the icon's place.",
|
|
3220
|
+
"default": "\"\""
|
|
3221
|
+
},
|
|
3213
3222
|
{
|
|
3214
3223
|
"kind": "field",
|
|
3215
3224
|
"name": "labels",
|
|
@@ -3231,6 +3240,12 @@
|
|
|
3231
3240
|
"privacy": "private",
|
|
3232
3241
|
"readonly": true
|
|
3233
3242
|
},
|
|
3243
|
+
{
|
|
3244
|
+
"kind": "field",
|
|
3245
|
+
"name": "#swatch",
|
|
3246
|
+
"privacy": "private",
|
|
3247
|
+
"readonly": true
|
|
3248
|
+
},
|
|
3234
3249
|
{
|
|
3235
3250
|
"kind": "field",
|
|
3236
3251
|
"name": "#lead",
|
|
@@ -3630,6 +3645,13 @@
|
|
|
3630
3645
|
"description": "SVG path data for an icon before the text.",
|
|
3631
3646
|
"name": "icon"
|
|
3632
3647
|
},
|
|
3648
|
+
{
|
|
3649
|
+
"type": {
|
|
3650
|
+
"text": "string"
|
|
3651
|
+
},
|
|
3652
|
+
"description": "A CSS color, drawn as a small round dot in the icon's place, such as a tag's own color.",
|
|
3653
|
+
"name": "swatch"
|
|
3654
|
+
},
|
|
3633
3655
|
{
|
|
3634
3656
|
"type": {
|
|
3635
3657
|
"text": "\"show\"|\"hide\"|\"auto\""
|
|
@@ -5344,7 +5366,7 @@
|
|
|
5344
5366
|
"text": "Properties"
|
|
5345
5367
|
},
|
|
5346
5368
|
"static": true,
|
|
5347
|
-
"default": "{ tone: { reflect: true }, icon: {}, loading: { type: \"boolean\", reflect: true }, size: { reflect: true }, }",
|
|
5369
|
+
"default": "{ tone: { reflect: true }, icon: {}, swatch: {}, loading: { type: \"boolean\", reflect: true }, size: { reflect: true }, }",
|
|
5348
5370
|
"inheritedFrom": {
|
|
5349
5371
|
"name": "GwElement",
|
|
5350
5372
|
"module": "src/element.ts"
|
|
@@ -5357,7 +5379,7 @@
|
|
|
5357
5379
|
"text": "readonly CSSStyleSheet[]"
|
|
5358
5380
|
},
|
|
5359
5381
|
"static": true,
|
|
5360
|
-
"default": "[ base, controlSizes(\"chip\"), css` :host { display: inline-flex; } /* 32px at medium, with 12px padding */ .chip { --gw-size: var(--gw-chip-scale, 1); --gw-scale: calc(var(--gw-size) * var(--gw-control-scale, 1)); --gw-icon-size: calc(1rem * var(--gw-scale)); display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-size)); align-items: center; box-sizing: border-box; height: calc(2rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-3) * var(--gw-size)); font-size: max( var(--gw-font-size-2xs), calc(var(--gw-font-size-xs) * var(--gw-size)) ); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-strong); background: var(--gw-tone-fill, var(--gw-color-fill-neutral-resting)); border: var(--gw-border-width) solid var(--gw-tone-border, var(--gw-color-border-quiet)); border-radius: var(--gw-radius-chip); } .content { display: inline-flex; gap: inherit; align-items: center; } `, ]",
|
|
5382
|
+
"default": "[ base, controlSizes(\"chip\"), css` :host { display: inline-flex; } /* 32px at medium, with 12px padding */ .chip { --gw-size: var(--gw-chip-scale, 1); --gw-scale: calc(var(--gw-size) * var(--gw-control-scale, 1)); --gw-icon-size: calc(1rem * var(--gw-scale)); display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-size)); align-items: center; box-sizing: border-box; height: calc(2rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-3) * var(--gw-size)); font-size: max( var(--gw-font-size-2xs), calc(var(--gw-font-size-xs) * var(--gw-size)) ); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-strong); background: var(--gw-tone-fill, var(--gw-color-fill-neutral-resting)); border: var(--gw-border-width) solid var(--gw-tone-border, var(--gw-color-border-quiet)); border-radius: var(--gw-radius-chip); } .content { display: inline-flex; gap: inherit; align-items: center; } /* A color dot in the icon's place */ .swatch { flex: none; width: calc(var(--gw-icon-size) * 0.6); height: calc(var(--gw-icon-size) * 0.6); border: 1px solid color-mix(in oklab, var(--gw-color-text-primary) 20%, transparent); border-radius: 50%; } `, ]",
|
|
5361
5383
|
"inheritedFrom": {
|
|
5362
5384
|
"name": "GwElement",
|
|
5363
5385
|
"module": "src/element.ts"
|
|
@@ -5380,6 +5402,15 @@
|
|
|
5380
5402
|
"description": "SVG path data for an icon before the text, instead of the `icon` slot.",
|
|
5381
5403
|
"default": "\"\""
|
|
5382
5404
|
},
|
|
5405
|
+
{
|
|
5406
|
+
"kind": "field",
|
|
5407
|
+
"name": "swatch",
|
|
5408
|
+
"type": {
|
|
5409
|
+
"text": "string"
|
|
5410
|
+
},
|
|
5411
|
+
"description": "A CSS color, drawn as a small round dot in the icon's place.",
|
|
5412
|
+
"default": "\"\""
|
|
5413
|
+
},
|
|
5383
5414
|
{
|
|
5384
5415
|
"kind": "field",
|
|
5385
5416
|
"name": "loading",
|
|
@@ -5402,6 +5433,12 @@
|
|
|
5402
5433
|
"privacy": "private",
|
|
5403
5434
|
"readonly": true
|
|
5404
5435
|
},
|
|
5436
|
+
{
|
|
5437
|
+
"kind": "field",
|
|
5438
|
+
"name": "#swatch",
|
|
5439
|
+
"privacy": "private",
|
|
5440
|
+
"readonly": true
|
|
5441
|
+
},
|
|
5405
5442
|
{
|
|
5406
5443
|
"kind": "field",
|
|
5407
5444
|
"name": "#chip",
|
|
@@ -5747,6 +5784,13 @@
|
|
|
5747
5784
|
"description": "SVG path data for an icon before the text.",
|
|
5748
5785
|
"name": "icon"
|
|
5749
5786
|
},
|
|
5787
|
+
{
|
|
5788
|
+
"type": {
|
|
5789
|
+
"text": "string"
|
|
5790
|
+
},
|
|
5791
|
+
"description": "A CSS color, drawn as a small round dot in the icon's place, such as a tag's own color.",
|
|
5792
|
+
"name": "swatch"
|
|
5793
|
+
},
|
|
5750
5794
|
{
|
|
5751
5795
|
"type": {
|
|
5752
5796
|
"text": "boolean"
|
|
@@ -20249,7 +20293,7 @@
|
|
|
20249
20293
|
"text": "readonly CSSStyleSheet[]"
|
|
20250
20294
|
},
|
|
20251
20295
|
"static": true,
|
|
20252
|
-
"default": "[ base, css` :host { display: block; } .page { display: flex; flex-direction: column; gap: var(--gw-space-6); width: 100
|
|
20296
|
+
"default": "[ base, css` :host { display: block; } .page { display: flex; flex-direction: column; gap: var(--gw-space-6); /* The same box as gw-app-bar's content, so the two line up */ width: min(100% - 2 * var(--gw-space-3), var(--gw-content-width)); margin-inline: auto; } :host([narrow]) .page { width: min( 100% - 2 * var(--gw-space-3), var(--gw-content-width-narrow) ); } `, ]",
|
|
20253
20297
|
"inheritedFrom": {
|
|
20254
20298
|
"name": "GwElement",
|
|
20255
20299
|
"module": "src/element.ts"
|
|
@@ -21988,7 +22032,7 @@
|
|
|
21988
22032
|
{
|
|
21989
22033
|
"kind": "variable",
|
|
21990
22034
|
"name": "base",
|
|
21991
|
-
"default": "css` :host { font-family: var(--gw-font-sans); color: var(--gw-color-text-primary); } *, *::before, *::after { box-sizing: border-box; } [hidden] { display: none !important; } :focus-visible { outline: var(--gw-focus-width) solid var(--gw-color-focus); outline-offset: var(--gw-focus-offset); } .icon { flex: none; width: var(--gw-icon-size, 1.25rem); height: var(--gw-icon-size, 1.25rem); fill: currentColor; } :host([tone=\"accent\"]) { --gw-tone: var(--gw-color-accent); --gw-tone-fill: var(--gw-color-fill-accent-quiet); --gw-tone-border: var(--gw-color-border-accent); } :host([tone=\"info\"]) { --gw-tone: var(--gw-color-info); --gw-tone-fill: var(--gw-color-fill-info-quiet); --gw-tone-border: var(--gw-color-border-info); } :host([tone=\"success\"]) { --gw-tone: var(--gw-color-success); --gw-tone-fill: var(--gw-color-fill-success-quiet); --gw-tone-border: var(--gw-color-border-success); } :host([tone=\"warning\"]) { --gw-tone: var(--gw-color-warning); --gw-tone-fill: var(--gw-color-fill-warning-quiet); --gw-tone-border: var(--gw-color-border-warning); } :host([tone=\"danger\"]) { --gw-tone: var(--gw-color-danger); --gw-tone-fill: var(--gw-color-fill-danger-quiet); --gw-tone-border: var(--gw-color-border-danger); } :host([tone=\"important\"]) { --gw-tone: var(--gw-color-important); --gw-tone-fill: var(--gw-color-fill-important-quiet); --gw-tone-border: var(--gw-color-border-important); } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; } } `",
|
|
22035
|
+
"default": "css` :host { font-family: var(--gw-font-sans); color: var(--gw-color-text-primary); } *, *::before, *::after { box-sizing: border-box; } :host([hidden]), [hidden] { display: none !important; } :focus-visible { outline: var(--gw-focus-width) solid var(--gw-color-focus); outline-offset: var(--gw-focus-offset); } .icon { flex: none; width: var(--gw-icon-size, 1.25rem); height: var(--gw-icon-size, 1.25rem); fill: currentColor; } :host([tone=\"accent\"]) { --gw-tone: var(--gw-color-accent); --gw-tone-fill: var(--gw-color-fill-accent-quiet); --gw-tone-border: var(--gw-color-border-accent); } :host([tone=\"info\"]) { --gw-tone: var(--gw-color-info); --gw-tone-fill: var(--gw-color-fill-info-quiet); --gw-tone-border: var(--gw-color-border-info); } :host([tone=\"success\"]) { --gw-tone: var(--gw-color-success); --gw-tone-fill: var(--gw-color-fill-success-quiet); --gw-tone-border: var(--gw-color-border-success); } :host([tone=\"warning\"]) { --gw-tone: var(--gw-color-warning); --gw-tone-fill: var(--gw-color-fill-warning-quiet); --gw-tone-border: var(--gw-color-border-warning); } :host([tone=\"danger\"]) { --gw-tone: var(--gw-color-danger); --gw-tone-fill: var(--gw-color-fill-danger-quiet); --gw-tone-border: var(--gw-color-border-danger); } :host([tone=\"important\"]) { --gw-tone: var(--gw-color-important); --gw-tone-fill: var(--gw-color-fill-important-quiet); --gw-tone-border: var(--gw-color-border-important); } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; } } `",
|
|
21992
22036
|
"description": "What every component shares: box sizing, the focus ring, icons and the\ntones that set `--gw-tone` from a `tone` attribute."
|
|
21993
22037
|
},
|
|
21994
22038
|
{
|
package/package.json
CHANGED
package/src/gw-button.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { base, controlSizes, createIcon, setIconPath } from "./styles.js";
|
|
|
38
38
|
* @attr {boolean} disabled - Disables the button.
|
|
39
39
|
* @attr {boolean} loading - Shows a spinning ring in the icon's place and ignores clicks.
|
|
40
40
|
* @attr {string} icon - SVG path data for an icon before the text.
|
|
41
|
+
* @attr {string} swatch - A CSS color, drawn as a small round dot in the icon's place, such as a tag's own color.
|
|
41
42
|
* @attr {"show"|"hide"|"auto"} labels - Whether the text shows beside an icon: always, never, or not on narrow screens. Defaults to `show`.
|
|
42
43
|
*
|
|
43
44
|
* @slot - The text, or an `<a>` holding it, in place of `href`.
|
|
@@ -61,6 +62,7 @@ export class GwButton extends GwElement {
|
|
|
61
62
|
disabled: { type: "boolean", reflect: true },
|
|
62
63
|
loading: { type: "boolean", reflect: true },
|
|
63
64
|
icon: {},
|
|
65
|
+
swatch: {},
|
|
64
66
|
labels: { reflect: true },
|
|
65
67
|
} as const;
|
|
66
68
|
|
|
@@ -242,10 +244,22 @@ export class GwButton extends GwElement {
|
|
|
242
244
|
place-items: center;
|
|
243
245
|
}
|
|
244
246
|
|
|
245
|
-
|
|
247
|
+
/* The icon slot is display: contents, so its slotted icon is a grid
|
|
248
|
+
item of its own and needs the shared cell too */
|
|
249
|
+
.lead > *,
|
|
250
|
+
::slotted([slot="icon"]) {
|
|
246
251
|
grid-area: 1 / 1;
|
|
247
252
|
}
|
|
248
253
|
|
|
254
|
+
/* A color dot in the icon's place */
|
|
255
|
+
.swatch {
|
|
256
|
+
width: calc(var(--gw-icon-size) * 0.6);
|
|
257
|
+
height: calc(var(--gw-icon-size) * 0.6);
|
|
258
|
+
border: 1px solid
|
|
259
|
+
color-mix(in oklab, var(--gw-color-text-primary) 20%, transparent);
|
|
260
|
+
border-radius: 50%;
|
|
261
|
+
}
|
|
262
|
+
|
|
249
263
|
.lead > *,
|
|
250
264
|
.text,
|
|
251
265
|
.ring {
|
|
@@ -341,6 +355,8 @@ export class GwButton extends GwElement {
|
|
|
341
355
|
declare loading: boolean;
|
|
342
356
|
/** SVG path data for an icon before the text. */
|
|
343
357
|
declare icon: string;
|
|
358
|
+
/** A CSS color, drawn as a small round dot in the icon's place. */
|
|
359
|
+
declare swatch: string;
|
|
344
360
|
/** Whether the text shows beside an icon: always, never, or not on narrow screens. */
|
|
345
361
|
declare labels: "show" | "hide" | "auto";
|
|
346
362
|
|
|
@@ -348,10 +364,13 @@ export class GwButton extends GwElement {
|
|
|
348
364
|
|
|
349
365
|
readonly #iconSlot = h("slot", { name: "icon" });
|
|
350
366
|
|
|
367
|
+
readonly #swatch = h("span", { class: "swatch", "aria-hidden": "true" });
|
|
368
|
+
|
|
351
369
|
readonly #lead = h(
|
|
352
370
|
"span",
|
|
353
371
|
{ class: "lead" },
|
|
354
372
|
this.#icon,
|
|
373
|
+
this.#swatch,
|
|
355
374
|
this.#iconSlot,
|
|
356
375
|
h("span", { class: "ring" }),
|
|
357
376
|
);
|
|
@@ -376,6 +395,7 @@ export class GwButton extends GwElement {
|
|
|
376
395
|
constructor() {
|
|
377
396
|
super();
|
|
378
397
|
this.icon = "";
|
|
398
|
+
this.swatch = "";
|
|
379
399
|
this.labels = "show";
|
|
380
400
|
this.variant = "brand";
|
|
381
401
|
this.appearance = "accent";
|
|
@@ -456,7 +476,9 @@ export class GwButton extends GwElement {
|
|
|
456
476
|
const control = this.#control;
|
|
457
477
|
|
|
458
478
|
const hasIcon =
|
|
459
|
-
this.icon !== "" ||
|
|
479
|
+
this.icon !== "" ||
|
|
480
|
+
this.swatch !== "" ||
|
|
481
|
+
this.querySelector("[slot='icon']") !== null;
|
|
460
482
|
|
|
461
483
|
control.classList.toggle("has-icon", hasIcon);
|
|
462
484
|
control.classList.toggle(
|
|
@@ -466,6 +488,8 @@ export class GwButton extends GwElement {
|
|
|
466
488
|
);
|
|
467
489
|
setIconPath(this.#icon, this.icon);
|
|
468
490
|
this.#icon.style.display = this.icon ? "" : "none";
|
|
491
|
+
this.#swatch.style.background = this.swatch;
|
|
492
|
+
this.#swatch.hidden = this.swatch === "" || this.icon !== "";
|
|
469
493
|
setAttribute(
|
|
470
494
|
control,
|
|
471
495
|
"title",
|
package/src/gw-chip.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
*
|
|
25
25
|
* @attr {"neutral"|"accent"|"info"|"success"|"warning"|"danger"|"important"} tone - The tint. Defaults to `neutral`.
|
|
26
26
|
* @attr {string} icon - SVG path data for an icon before the text.
|
|
27
|
+
* @attr {string} swatch - A CSS color, drawn as a small round dot in the icon's place, such as a tag's own color.
|
|
27
28
|
* @attr {boolean} loading - Shows a skeleton for the text.
|
|
28
29
|
* @attr {"xs"|"small"|"medium"|"large"|"xl"} size - The size, around 32px tall at medium. Defaults to `medium`.
|
|
29
30
|
*
|
|
@@ -41,6 +42,7 @@ export class GwChip extends GwElement {
|
|
|
41
42
|
static override properties = {
|
|
42
43
|
tone: { reflect: true },
|
|
43
44
|
icon: {},
|
|
45
|
+
swatch: {},
|
|
44
46
|
loading: { type: "boolean", reflect: true },
|
|
45
47
|
size: { reflect: true },
|
|
46
48
|
} as const;
|
|
@@ -82,17 +84,31 @@ export class GwChip extends GwElement {
|
|
|
82
84
|
gap: inherit;
|
|
83
85
|
align-items: center;
|
|
84
86
|
}
|
|
87
|
+
|
|
88
|
+
/* A color dot in the icon's place */
|
|
89
|
+
.swatch {
|
|
90
|
+
flex: none;
|
|
91
|
+
width: calc(var(--gw-icon-size) * 0.6);
|
|
92
|
+
height: calc(var(--gw-icon-size) * 0.6);
|
|
93
|
+
border: 1px solid
|
|
94
|
+
color-mix(in oklab, var(--gw-color-text-primary) 20%, transparent);
|
|
95
|
+
border-radius: 50%;
|
|
96
|
+
}
|
|
85
97
|
`,
|
|
86
98
|
];
|
|
87
99
|
|
|
88
100
|
declare tone: Tone;
|
|
89
101
|
/** SVG path data for an icon before the text, instead of the `icon` slot. */
|
|
90
102
|
declare icon: string;
|
|
103
|
+
/** A CSS color, drawn as a small round dot in the icon's place. */
|
|
104
|
+
declare swatch: string;
|
|
91
105
|
declare loading: boolean;
|
|
92
106
|
declare size: "xs" | "small" | "medium" | "large" | "xl";
|
|
93
107
|
|
|
94
108
|
readonly #icon = createIcon("");
|
|
95
109
|
|
|
110
|
+
readonly #swatch = h("span", { class: "swatch", "aria-hidden": "true" });
|
|
111
|
+
|
|
96
112
|
readonly #chip = h("span", { class: "chip", part: "chip" });
|
|
97
113
|
|
|
98
114
|
readonly #skeleton = h("gw-skeleton-text", {
|
|
@@ -102,7 +118,7 @@ export class GwChip extends GwElement {
|
|
|
102
118
|
readonly #content = h(
|
|
103
119
|
"span",
|
|
104
120
|
{ class: "content" },
|
|
105
|
-
h("slot", { name: "icon" }, this.#icon),
|
|
121
|
+
h("slot", { name: "icon" }, this.#icon, this.#swatch),
|
|
106
122
|
h("slot"),
|
|
107
123
|
);
|
|
108
124
|
|
|
@@ -110,6 +126,7 @@ export class GwChip extends GwElement {
|
|
|
110
126
|
super();
|
|
111
127
|
this.tone = "neutral";
|
|
112
128
|
this.icon = "";
|
|
129
|
+
this.swatch = "";
|
|
113
130
|
this.loading = false;
|
|
114
131
|
this.size = "medium";
|
|
115
132
|
}
|
|
@@ -124,6 +141,8 @@ export class GwChip extends GwElement {
|
|
|
124
141
|
|
|
125
142
|
setIconPath(this.#icon, this.icon);
|
|
126
143
|
this.#icon.toggleAttribute("hidden", !this.icon);
|
|
144
|
+
this.#swatch.style.background = this.swatch;
|
|
145
|
+
this.#swatch.hidden = this.swatch === "" || this.icon !== "";
|
|
127
146
|
|
|
128
147
|
setAttribute(this.#chip, "aria-busy", this.loading ? "true" : null);
|
|
129
148
|
this.#skeleton.hidden = !this.loading;
|
package/src/layout.ts
CHANGED
|
@@ -36,13 +36,16 @@ export class GwPage extends GwElement {
|
|
|
36
36
|
display: flex;
|
|
37
37
|
flex-direction: column;
|
|
38
38
|
gap: var(--gw-space-6);
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
/* The same box as gw-app-bar's content, so the two line up */
|
|
40
|
+
width: min(100% - 2 * var(--gw-space-3), var(--gw-content-width));
|
|
41
41
|
margin-inline: auto;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
:host([narrow]) .page {
|
|
45
|
-
|
|
45
|
+
width: min(
|
|
46
|
+
100% - 2 * var(--gw-space-3),
|
|
47
|
+
var(--gw-content-width-narrow)
|
|
48
|
+
);
|
|
46
49
|
}
|
|
47
50
|
`,
|
|
48
51
|
];
|