@timmo001/groundwork-ui 0.4.1 → 0.5.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.
@@ -2949,7 +2949,7 @@
2949
2949
  "declarations": [
2950
2950
  {
2951
2951
  "kind": "class",
2952
- "description": "A native button styled through `--gw-*` variables, so it follows the\ntheme and mode around it. With `href` it renders a link that looks the\nsame. Put an icon in the `icon` slot.\n\n`variant` picks the color and `appearance` how it's applied, from most to\nleast important: `accent` (a solid fill), `filled` (a soft tint),\n`outlined` (a stroke) or `plain` (text only). Every button is a pill.\nSizes run `xs` to `xl`, and `--gw-button-scale` sets any size in between.\n\nWhile `loading`, a spinning ring takes the icon's place, or the text's\nwhen there's no icon, so the button keeps its size, and clicks are\nignored. The icon fades back once it's done.",
2952
+ "description": "A native button styled through `--gw-*` variables, so it follows the\ntheme and mode around it. With `href` it renders a link that looks the\nsame. Put an icon in the `icon` slot.\n\nFor a link the page's HTML has to carry, such as one with `rel=\"me\"`, a\n`target` or `aria-current=\"page\"`, put a plain `<a>` inside instead of\n`href`. The button styles it, a click anywhere on the pill follows it, and\n`aria-current` on it gets a current style.\n\n`variant` picks the color and `appearance` how it's applied, from most to\nleast important: `accent` (a solid fill), `filled` (a soft tint),\n`outlined` (a stroke) or `plain` (text only). Every button is a pill.\nSizes run `xs` to `xl`, and `--gw-button-scale` sets any size in between.\n\nWhile `loading`, a spinning ring takes the icon's place, or the text's\nwhen there's no icon, so the button keeps its size, and clicks are\nignored. The icon fades back once it's done.",
2953
2953
  "name": "GwButton",
2954
2954
  "cssProperties": [
2955
2955
  {
@@ -2967,13 +2967,13 @@
2967
2967
  ],
2968
2968
  "cssParts": [
2969
2969
  {
2970
- "description": "The native button or link.",
2970
+ "description": "The native button or link, or the pill around a slotted link.",
2971
2971
  "name": "button"
2972
2972
  }
2973
2973
  ],
2974
2974
  "slots": [
2975
2975
  {
2976
- "description": "The text.",
2976
+ "description": "The text, or an `<a>` holding it, in place of `href`.",
2977
2977
  "name": ""
2978
2978
  },
2979
2979
  {
@@ -3016,7 +3016,7 @@
3016
3016
  "text": "readonly CSSStyleSheet[]"
3017
3017
  },
3018
3018
  "static": true,
3019
- "default": "[ base, css` :host { --gw-button-tone: var(--gw-color-accent); display: inline-block; } /* Everything scales from --gw-button-scale, around a 40px medium button: the presets give 24, 32, 48 and 56px, and an app can set any value for a size between or beyond them */ :host([size=\"xs\"]) { --gw-button-scale: 0.6; } :host([size=\"small\"]) { --gw-button-scale: 0.8; } :host([size=\"large\"]) { --gw-button-scale: 1.2; } :host([size=\"xl\"]) { --gw-button-scale: 1.4; } :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-scale: var(--gw-button-scale, 1); --gw-icon-size: calc(1.125rem * var(--gw-scale)); position: relative; display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-scale)); align-items: center; justify-content: center; min-height: calc(2.5rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-4) * var(--gw-scale)); font: inherit; font-size: calc(var(--gw-font-size-s) * var(--gw-scale)); 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); } .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 > * { grid-area: 1 / 1; } .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; } } `, ]",
3019
+ "default": "[ base, css` :host { --gw-button-tone: var(--gw-color-accent); display: inline-block; } /* Everything scales from --gw-button-scale, around a 40px medium button: the presets give 24, 32, 48 and 56px, and an app can set any value for a size between or beyond them */ :host([size=\"xs\"]) { --gw-button-scale: 0.6; } :host([size=\"small\"]) { --gw-button-scale: 0.8; } :host([size=\"large\"]) { --gw-button-scale: 1.2; } :host([size=\"xl\"]) { --gw-button-scale: 1.4; } :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-scale: var(--gw-button-scale, 1); --gw-icon-size: calc(1.125rem * var(--gw-scale)); position: relative; display: inline-flex; gap: calc(var(--gw-space-2) * var(--gw-scale)); align-items: center; justify-content: center; min-height: calc(2.5rem * var(--gw-scale)); padding: 0 calc(var(--gw-space-4) * var(--gw-scale)); font: inherit; font-size: calc(var(--gw-font-size-s) * var(--gw-scale)); 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 > * { grid-area: 1 / 1; } .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; } } `, ]",
3020
3020
  "inheritedFrom": {
3021
3021
  "name": "GwElement",
3022
3022
  "module": "src/element.ts"
@@ -3140,9 +3140,20 @@
3140
3140
  "name": "#control",
3141
3141
  "privacy": "private",
3142
3142
  "type": {
3143
- "text": "HTMLButtonElement | HTMLAnchorElement"
3143
+ "text": "HTMLButtonElement | HTMLAnchorElement | HTMLSpanElement"
3144
3144
  }
3145
3145
  },
3146
+ {
3147
+ "kind": "method",
3148
+ "name": "#link",
3149
+ "privacy": "private",
3150
+ "return": {
3151
+ "type": {
3152
+ "text": "HTMLAnchorElement | null"
3153
+ }
3154
+ },
3155
+ "description": "A plain `<a>` the page put inside, which the button wraps instead of `href`."
3156
+ },
3146
3157
  {
3147
3158
  "kind": "method",
3148
3159
  "name": "create",
@@ -13193,6 +13204,12 @@
13193
13204
  "kind": "class",
13194
13205
  "description": "A confirmation, rename or small form that opens next to the button that\nasked for it, rather than as a dialog in the middle of the screen. On\nnarrow screens it's a bottom sheet. Opened without a button, such as after\na save, it sits in the middle like a dialog.\n\nIt's on the Popover API, in the top layer, and closes on Esc or a click\noutside. Open it with `show(anchor)`. Put buttons in the `actions` slot: a\nclick on one with a `value` closes it with that value, and fires `close`.\n`confirm` makes it an `alertdialog`, for a question that needs an answer.",
13195
13206
  "name": "GwPopover",
13207
+ "cssProperties": [
13208
+ {
13209
+ "description": "Its width beside a button. Defaults to `20rem`.",
13210
+ "name": "--gw-popover-width"
13211
+ }
13212
+ ],
13196
13213
  "slots": [
13197
13214
  {
13198
13215
  "description": "The content.",
@@ -13224,7 +13241,7 @@
13224
13241
  "text": "readonly CSSStyleSheet[]"
13225
13242
  },
13226
13243
  "static": true,
13227
- "default": "[ base, dismissalStyles, css` [popover] { position: fixed; inset: unset; box-sizing: border-box; width: min(20rem, calc(100vw - 2 * ${gap}px)); padding: var(--gw-space-4); margin: 0; color: var(--gw-color-text-primary); background: var(--gw-color-surface-overlay); border: max(var(--gw-border-width), 1px) solid var(--gw-color-border-normal); border-radius: var(--gw-radius-panel); box-shadow: var(--gw-shadow-l); opacity: 0; scale: 0.96; transition: opacity var(--gw-motion-fast) var(--gw-motion-easing), scale var(--gw-motion-normal) var(--gw-motion-easing), translate var(--gw-motion-normal) var(--gw-motion-easing), display var(--gw-motion-normal) allow-discrete, overlay var(--gw-motion-normal) allow-discrete; } [popover]:popover-open { opacity: 1; scale: 1; } @starting-style { [popover]:popover-open { opacity: 0; scale: 0.96; } } /* Grows from the corner nearest the button */ [data-placement=\"below\"] { transform-origin: top right; } [data-placement=\"above\"] { transform-origin: bottom right; } [data-placement=\"below\"][data-side=\"start\"] { transform-origin: top left; } [data-placement=\"above\"][data-side=\"start\"] { transform-origin: bottom left; } [data-placement=\"center\"] { inset: 0; margin: auto; height: fit-content; } [data-placement=\"center\"]::backdrop { background: rgb(0 0 0 / 40%); } /* A bottom sheet on narrow screens, sliding up from the edge */ [data-placement=\"sheet\"] { inset: auto 0 0; width: 100%; max-width: none; padding-block-end: calc( var(--gw-space-4) + env(safe-area-inset-bottom) ); border-end-start-radius: 0; border-end-end-radius: 0; scale: 1; translate: 0 100%; } [data-placement=\"sheet\"]:popover-open { translate: 0 0; } @starting-style { [data-placement=\"sheet\"]:popover-open { translate: 0 100%; } } [data-placement=\"sheet\"]::backdrop { background: rgb(0 0 0 / 40%); } header { display: flex; gap: var(--gw-space-2); align-items: flex-start; margin: calc(var(--gw-space-2) * -1) calc(var(--gw-space-2) * -1) var(--gw-space-2) 0; } header .content { flex: 1; min-width: 0; padding-block-start: var(--gw-space-2); } h2 { margin: 0 0 var(--gw-space-2); font-size: var(--gw-font-size-m); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-strong); } .body { font-size: var(--gw-font-size-s); } ::slotted(p) { margin: 0; } footer { display: flex; flex-wrap: wrap; gap: var(--gw-space-2); justify-content: flex-end; margin-block-start: var(--gw-space-4); } `, ]",
13244
+ "default": "[ base, dismissalStyles, css` [popover] { position: fixed; inset: unset; box-sizing: border-box; width: min(var(--gw-popover-width, 20rem), calc(100vw - 2 * ${gap}px)); padding: var(--gw-space-4); margin: 0; color: var(--gw-color-text-primary); background: var(--gw-color-surface-overlay); border: max(var(--gw-border-width), 1px) solid var(--gw-color-border-normal); border-radius: var(--gw-radius-panel); box-shadow: var(--gw-shadow-l); opacity: 0; scale: 0.96; transition: opacity var(--gw-motion-fast) var(--gw-motion-easing), scale var(--gw-motion-normal) var(--gw-motion-easing), translate var(--gw-motion-normal) var(--gw-motion-easing), display var(--gw-motion-normal) allow-discrete, overlay var(--gw-motion-normal) allow-discrete; } [popover]:popover-open { opacity: 1; scale: 1; } @starting-style { [popover]:popover-open { opacity: 0; scale: 0.96; } } /* Grows from the corner nearest the button */ [data-placement=\"below\"] { transform-origin: top right; } [data-placement=\"above\"] { transform-origin: bottom right; } [data-placement=\"below\"][data-side=\"start\"] { transform-origin: top left; } [data-placement=\"above\"][data-side=\"start\"] { transform-origin: bottom left; } [data-placement=\"center\"] { inset: 0; margin: auto; height: fit-content; } [data-placement=\"center\"]::backdrop { background: rgb(0 0 0 / 40%); } /* A bottom sheet on narrow screens, sliding up from the edge */ [data-placement=\"sheet\"] { inset: auto 0 0; width: 100%; max-width: none; padding-block-end: calc( var(--gw-space-4) + env(safe-area-inset-bottom) ); border-end-start-radius: 0; border-end-end-radius: 0; scale: 1; translate: 0 100%; } [data-placement=\"sheet\"]:popover-open { translate: 0 0; } @starting-style { [data-placement=\"sheet\"]:popover-open { translate: 0 100%; } } [data-placement=\"sheet\"]::backdrop { background: rgb(0 0 0 / 40%); } header { display: flex; gap: var(--gw-space-2); align-items: flex-start; margin: calc(var(--gw-space-2) * -1) calc(var(--gw-space-2) * -1) var(--gw-space-2) 0; } header .content { flex: 1; min-width: 0; padding-block-start: var(--gw-space-2); } h2 { margin: 0 0 var(--gw-space-2); font-size: var(--gw-font-size-m); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-strong); } .body { font-size: var(--gw-font-size-s); } ::slotted(p) { margin: 0; } footer { display: flex; flex-wrap: wrap; gap: var(--gw-space-2); justify-content: flex-end; margin-block-start: var(--gw-space-4); } `, ]",
13228
13245
  "inheritedFrom": {
13229
13246
  "name": "GwElement",
13230
13247
  "module": "src/element.ts"
@@ -17760,12 +17777,36 @@
17760
17777
  },
17761
17778
  {
17762
17779
  "kind": "javascript-module",
17763
- "path": "src/gw-theme-picker.ts",
17780
+ "path": "src/gw-theme-gallery.ts",
17764
17781
  "declarations": [
17765
17782
  {
17766
17783
  "kind": "class",
17767
- "description": "A palette button for a page's look. It opens a popover with the mode\n(auto, light, dark or Darker), the theme, and buttons to import a theme\nfile (a Groundwork theme's `.json` or an Omarchy `colors.toml`) or reset.\n\nIt only asks: it fires `mode`, `theme`, `import` and `reset`, and the page\napplies them and sets `mode`, `theme` and `themes` back. `pageTheme` from\n`@timmo001/groundwork-tokens/page` does all of that. Show an import's\nresult, such as contrast misses, in `status`.",
17768
- "name": "GwThemePicker",
17784
+ "description": "Picks a theme from a grid of cards, each a small picture of an app in that\ntheme's colors: a rail, a panel and the status tones. For a settings page,\nor inside `gw-theme-picker` with `gallery`.\n\nThemes with a `group` sit together under its name, and lone ones under\n\"Other\", so a family's light and dark variants line up. Previews draw in\n`mode`, or the mode of the page or themed container it sits in, from the\ntheme CSS already on the page, including a custom theme `pageTheme`\nimported. Call `refresh()` after that CSS changes.\n\nIt's a `<fieldset>` of native radio buttons, so arrow keys move the choice.\nIt fires `theme`.",
17785
+ "name": "GwThemeGallery",
17786
+ "cssProperties": [
17787
+ {
17788
+ "description": "The narrowest a card gets. Defaults to `9rem`.",
17789
+ "name": "--gw-theme-gallery-min"
17790
+ }
17791
+ ],
17792
+ "cssParts": [
17793
+ {
17794
+ "description": "Each theme's card.",
17795
+ "name": "card"
17796
+ },
17797
+ {
17798
+ "description": "The picture of an app in the theme.",
17799
+ "name": "preview"
17800
+ },
17801
+ {
17802
+ "description": "The theme's name under it.",
17803
+ "name": "name"
17804
+ },
17805
+ {
17806
+ "description": "Each group's heading.",
17807
+ "name": "group"
17808
+ }
17809
+ ],
17769
17810
  "members": [
17770
17811
  {
17771
17812
  "kind": "field",
@@ -17774,7 +17815,7 @@
17774
17815
  "text": "Properties"
17775
17816
  },
17776
17817
  "static": true,
17777
- "default": "{ mode: { reflect: true }, theme: { reflect: true }, themes: { type: \"json\" }, status: {}, label: {}, }",
17818
+ "default": "{ label: {}, theme: { reflect: true }, themes: { type: \"json\" }, mode: { reflect: true }, }",
17778
17819
  "inheritedFrom": {
17779
17820
  "name": "GwElement",
17780
17821
  "module": "src/element.ts"
@@ -17787,7 +17828,7 @@
17787
17828
  "text": "readonly CSSStyleSheet[]"
17788
17829
  },
17789
17830
  "static": true,
17790
- "default": "[ base, css` :host { display: inline-block; } .controls { display: flex; flex-direction: column; gap: var(--gw-space-4); margin-block-start: var(--gw-space-2); } .status { margin: 0; font-size: var(--gw-font-size-s); color: var(--gw-color-text-secondary); } `, ]",
17831
+ "default": "[ base, css` :host { display: block; } fieldset { display: flex; flex-direction: column; gap: var(--gw-space-4); min-width: 0; padding: 0; margin: 0; border: 0; } legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } .group { display: grid; grid-template-columns: repeat( auto-fill, minmax(var(--gw-theme-gallery-min, 9rem), 1fr) ); gap: var(--gw-space-3); } .group-name { grid-column: 1 / -1; margin: 0; font-size: var(--gw-font-size-s); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-secondary); text-transform: var(--gw-label-transform); letter-spacing: var(--gw-label-tracking); } label { position: relative; display: flex; flex-direction: column; gap: var(--gw-space-2); padding: var(--gw-space-2); cursor: pointer; background: var(--gw-color-surface-raised); border: 2px solid var(--gw-color-border-normal); border-radius: var(--gw-radius-panel); transition: border-color var(--gw-motion-fast) var(--gw-motion-easing), background-color var(--gw-motion-fast) var(--gw-motion-easing); } label:hover { border-color: var(--gw-color-border-accent); } label:has(input:checked) { background: var(--gw-color-fill-accent-quiet); border-color: var(--gw-color-accent); } label:has(input:focus-visible) { outline: var(--gw-focus-width) solid var(--gw-color-focus); outline-offset: var(--gw-focus-offset); } input { position: absolute; inset: 0; margin: 0; cursor: pointer; opacity: 0; } /* A small app in the theme's own colors */ .preview { display: grid; grid-template-columns: 22% 1fr; gap: 6px; height: 5.5rem; padding: 6px; background: var(--p-bg); border-radius: calc(var(--gw-radius-panel) - 2px); } .rail { display: flex; flex-direction: column; gap: 4px; padding: 4px; } .rail i { height: 5px; background: var(--p-muted); border-radius: 3px; opacity: 0.5; } .rail i:first-child { background: var(--p-accent); opacity: 1; } .panel { display: flex; flex-direction: column; gap: 5px; min-width: 0; padding: 6px; background: var(--p-surface); border: 1px solid var(--p-border); border-radius: min(var(--p-radius), 6px); } .line { width: 60%; height: 5px; background: var(--p-text); border-radius: 3px; } .line.short { width: 40%; background: var(--p-muted); } .bars { display: flex; flex: 1; gap: 3px; align-items: flex-end; } .bars i { flex: 1; border-radius: 2px 2px 0 0; } .name { display: flex; flex-direction: column; padding: 0 var(--gw-space-1) var(--gw-space-1); font-size: var(--gw-font-size-s); font-weight: var(--gw-font-weight-strong); color: var(--gw-color-text-strong); } .name small { font-size: var(--gw-font-size-xs); font-weight: normal; color: var(--gw-color-text-secondary); } label:has(input:checked) .name { color: var(--gw-color-accent); } .check { position: absolute; inset-block-start: var(--gw-space-3); inset-inline-end: var(--gw-space-3); display: none; place-items: center; width: 1.5rem; height: 1.5rem; color: var(--gw-color-on-accent); background: var(--gw-color-fill-accent-resting); border-radius: 50%; --gw-icon-size: 1rem; } label:has(input:checked) .check { display: grid; } `, ]",
17791
17832
  "inheritedFrom": {
17792
17833
  "name": "GwElement",
17793
17834
  "module": "src/element.ts"
@@ -17795,11 +17836,11 @@
17795
17836
  },
17796
17837
  {
17797
17838
  "kind": "field",
17798
- "name": "mode",
17839
+ "name": "label",
17799
17840
  "type": {
17800
17841
  "text": "string"
17801
17842
  },
17802
- "default": "\"auto\""
17843
+ "default": "\"Theme\""
17803
17844
  },
17804
17845
  {
17805
17846
  "kind": "field",
@@ -17819,7 +17860,7 @@
17819
17860
  },
17820
17861
  {
17821
17862
  "kind": "field",
17822
- "name": "status",
17863
+ "name": "mode",
17823
17864
  "type": {
17824
17865
  "text": "string"
17825
17866
  },
@@ -17827,68 +17868,77 @@
17827
17868
  },
17828
17869
  {
17829
17870
  "kind": "field",
17830
- "name": "label",
17831
- "type": {
17832
- "text": "string"
17833
- },
17834
- "default": "\"Theme\""
17871
+ "name": "#legend",
17872
+ "privacy": "private",
17873
+ "readonly": true
17835
17874
  },
17836
17875
  {
17837
17876
  "kind": "field",
17838
- "name": "#button",
17877
+ "name": "#fieldset",
17839
17878
  "privacy": "private",
17840
17879
  "readonly": true
17841
17880
  },
17842
17881
  {
17843
17882
  "kind": "field",
17844
- "name": "#mode",
17883
+ "name": "#name",
17845
17884
  "privacy": "private",
17846
- "readonly": true
17885
+ "readonly": true,
17886
+ "default": "`gw-theme-gallery-${Math.random().toString(36).slice(2)}`"
17847
17887
  },
17848
17888
  {
17849
17889
  "kind": "field",
17850
- "name": "#theme",
17890
+ "name": "#cards",
17851
17891
  "privacy": "private",
17852
- "readonly": true
17892
+ "type": {
17893
+ "text": "{\n input: HTMLInputElement;\n preview: HTMLElement;\n id: string;\n }[]"
17894
+ },
17895
+ "default": "[]"
17853
17896
  },
17854
17897
  {
17855
17898
  "kind": "field",
17856
- "name": "#status",
17899
+ "name": "#scheme",
17857
17900
  "privacy": "private",
17858
17901
  "readonly": true
17859
17902
  },
17860
17903
  {
17861
17904
  "kind": "field",
17862
- "name": "#file",
17905
+ "name": "#onScheme",
17863
17906
  "privacy": "private",
17864
17907
  "readonly": true
17865
17908
  },
17866
17909
  {
17867
17910
  "kind": "field",
17868
- "name": "#popover",
17911
+ "name": "#modeRoot",
17869
17912
  "privacy": "private",
17870
- "readonly": true
17913
+ "readonly": true,
17914
+ "default": "new MutationObserver(() => { if (!this.mode) this.refresh(); })"
17871
17915
  },
17872
17916
  {
17873
17917
  "kind": "method",
17874
- "name": "show",
17875
- "description": "Opens the popover under the button."
17918
+ "name": "#mode",
17919
+ "privacy": "private",
17920
+ "description": "`mode`, or the mode of the page or themed container around it."
17876
17921
  },
17877
17922
  {
17878
17923
  "kind": "method",
17879
- "name": "#detail",
17924
+ "name": "refresh",
17925
+ "description": "Redraws the previews from the page's theme CSS, such as after an import."
17926
+ },
17927
+ {
17928
+ "kind": "method",
17929
+ "name": "#card",
17880
17930
  "privacy": "private",
17881
17931
  "parameters": [
17882
17932
  {
17883
- "name": "type",
17933
+ "name": "theme",
17884
17934
  "type": {
17885
- "text": "string"
17935
+ "text": "OptionItem"
17886
17936
  }
17887
17937
  },
17888
17938
  {
17889
- "name": "detail",
17939
+ "name": "inOther",
17890
17940
  "type": {
17891
- "text": "Detail"
17941
+ "text": "boolean"
17892
17942
  }
17893
17943
  }
17894
17944
  ]
@@ -17917,7 +17967,7 @@
17917
17967
  "privacy": "protected",
17918
17968
  "parameters": [
17919
17969
  {
17920
- "name": "_changed",
17970
+ "name": "changed",
17921
17971
  "type": {
17922
17972
  "text": "ReadonlySet<string>"
17923
17973
  }
@@ -18207,99 +18257,77 @@
18207
18257
  ],
18208
18258
  "events": [
18209
18259
  {
18210
- "name": "reset",
18211
- "type": {
18212
- "text": "Event"
18213
- },
18214
- "description": "When Reset is pressed."
18215
- },
18216
- {
18217
- "type": {
18218
- "text": "CustomEvent<{ mode: string }>"
18219
- },
18220
- "description": "When a mode is picked.",
18221
- "name": "mode"
18222
- },
18223
- {
18260
+ "name": "theme",
18224
18261
  "type": {
18225
18262
  "text": "CustomEvent<{ id: string }>"
18226
18263
  },
18227
- "description": "When a theme is picked.",
18228
- "name": "theme"
18229
- },
18230
- {
18231
- "type": {
18232
- "text": "CustomEvent<{ text: string, name: string }>"
18233
- },
18234
- "description": "When a theme file is chosen, with its text and file name.",
18235
- "name": "import"
18264
+ "description": "When a theme is picked."
18236
18265
  }
18237
18266
  ],
18238
18267
  "attributes": [
18239
18268
  {
18240
18269
  "type": {
18241
- "text": "\"auto\"|\"light\"|\"dark\"|\"darker\""
18270
+ "text": "string"
18242
18271
  },
18243
- "description": "The mode in use. Defaults to `auto`.",
18244
- "name": "mode"
18272
+ "description": "The group's accessible name. Defaults to `Theme`.",
18273
+ "name": "label"
18245
18274
  },
18246
18275
  {
18247
18276
  "type": {
18248
18277
  "text": "string"
18249
18278
  },
18250
- "description": "The theme in use, by id.",
18279
+ "description": "The chosen theme, by id.",
18251
18280
  "name": "theme"
18252
18281
  },
18253
18282
  {
18254
18283
  "type": {
18255
18284
  "text": "OptionItem[]"
18256
18285
  },
18257
- "description": "The themes to offer, as JSON.",
18286
+ "description": "The themes, as JSON: `value` is the id, `label` the name, and `group` the family.",
18258
18287
  "name": "themes"
18259
18288
  },
18260
18289
  {
18261
18290
  "type": {
18262
- "text": "string"
18263
- },
18264
- "description": "A line under the controls, such as an import's result.",
18265
- "name": "status"
18266
- },
18267
- {
18268
- "type": {
18269
- "text": "string"
18291
+ "text": "\"auto\"|\"light\"|\"dark\"|\"darker\""
18270
18292
  },
18271
- "description": "The button's accessible name and the popover's heading. Defaults to `Theme`.",
18272
- "name": "label"
18293
+ "description": "The mode the previews show. Defaults to the mode it sits in.",
18294
+ "name": "mode"
18273
18295
  }
18274
18296
  ],
18275
18297
  "superclass": {
18276
18298
  "name": "GwElement",
18277
18299
  "module": "/src/element.js"
18278
18300
  },
18279
- "tagName": "gw-theme-picker",
18301
+ "tagName": "gw-theme-gallery",
18280
18302
  "customElement": true,
18281
- "summary": "A button opening the page's mode, theme and import."
18303
+ "summary": "Picks a theme from cards that preview each one."
18282
18304
  }
18283
18305
  ],
18284
18306
  "exports": [
18285
18307
  {
18286
18308
  "kind": "js",
18287
- "name": "GwThemePicker",
18309
+ "name": "GwThemeGallery",
18288
18310
  "declaration": {
18289
- "name": "GwThemePicker",
18290
- "module": "src/gw-theme-picker.ts"
18311
+ "name": "GwThemeGallery",
18312
+ "module": "src/gw-theme-gallery.ts"
18291
18313
  }
18292
18314
  }
18293
18315
  ]
18294
18316
  },
18295
18317
  {
18296
18318
  "kind": "javascript-module",
18297
- "path": "src/gw-toast.ts",
18319
+ "path": "src/gw-theme-picker.ts",
18298
18320
  "declarations": [
18299
18321
  {
18300
18322
  "kind": "class",
18301
- "description": "Where toasts appear: the bottom corner on the end side, away from what\npeople click. Call `show(message, tone)`; each toast is announced politely\nand fades out after `duration` milliseconds.\n\nA toast only tells; it has no actions and lets every click through, since\nit may sit over something interactive and leaves before it can be used.\nIt's in the top layer and rises above any dialog each time one shows. It's\na last resort: show an outcome where it happened instead.",
18302
- "name": "GwToaster",
18323
+ "description": "A palette button for a page's look. It opens a popover with the mode\n(auto, light, dark or Darker), the theme, and buttons to import a theme\nfile (a Groundwork theme's `.json` or an Omarchy `colors.toml`) or reset.\n\nIt only asks: it fires `mode`, `theme`, `import` and `reset`, and the page\napplies them and sets `mode`, `theme` and `themes` back. `pageTheme` from\n`@timmo001/groundwork-tokens/page` does all of that. Show an import's\nresult, such as contrast misses, in `status`.\n\n`gallery` swaps the theme select for `gw-theme-gallery`'s cards, which\npreview each theme in the chosen mode.",
18324
+ "name": "GwThemePicker",
18325
+ "cssParts": [
18326
+ {
18327
+ "description": "The theme gallery, with `gallery`.",
18328
+ "name": "gallery"
18329
+ }
18330
+ ],
18303
18331
  "members": [
18304
18332
  {
18305
18333
  "kind": "field",
@@ -18308,7 +18336,7 @@
18308
18336
  "text": "Properties"
18309
18337
  },
18310
18338
  "static": true,
18311
- "default": "{ duration: { type: \"number\" }, }",
18339
+ "default": "{ mode: { reflect: true }, theme: { reflect: true }, themes: { type: \"json\" }, gallery: { type: \"boolean\", reflect: true }, status: {}, label: {}, }",
18312
18340
  "inheritedFrom": {
18313
18341
  "name": "GwElement",
18314
18342
  "module": "src/element.ts"
@@ -18321,7 +18349,7 @@
18321
18349
  "text": "readonly CSSStyleSheet[]"
18322
18350
  },
18323
18351
  "static": true,
18324
- "default": "[ base, css` :host { position: fixed; inset: auto var(--gw-space-4) var(--gw-space-4) auto; width: min(22rem, calc(100vw - 2 * var(--gw-space-4))); padding: 0; margin: 0; overflow: visible; color: inherit; pointer-events: none; user-select: none; background: none; border: 0; } :host(:dir(rtl)) { inset: auto auto var(--gw-space-4) var(--gw-space-4); } :host(:not(:popover-open)) { display: none; } .list { display: flex; flex-direction: column; gap: var(--gw-space-1); align-items: flex-end; } .toast { max-width: 100%; padding: var(--gw-space-2) var(--gw-space-3); font-size: var(--gw-font-size-s); color: var(--gw-color-text-strong); background: var(--gw-color-surface-overlay); border: var(--gw-border-width) solid var(--gw-color-border-normal); border-inline-start: calc(var(--gw-border-width) * 4) solid var(--gw-toast-tone); border-radius: var(--gw-radius-control); box-shadow: var(--gw-shadow-m); } `, ]",
18352
+ "default": "[ base, css` :host { display: inline-block; } :host([gallery]) gw-popover { --gw-popover-width: 34rem; } .gallery { max-height: min(24rem, 50vh); overflow: auto; /* Room for the cards' focus rings */ padding: var(--gw-space-1); margin: calc(var(--gw-space-1) * -1); } .controls { display: flex; flex-direction: column; gap: var(--gw-space-4); margin-block-start: var(--gw-space-2); } .status { margin: 0; font-size: var(--gw-font-size-s); color: var(--gw-color-text-secondary); } `, ]",
18325
18353
  "inheritedFrom": {
18326
18354
  "name": "GwElement",
18327
18355
  "module": "src/element.ts"
@@ -18329,24 +18357,118 @@
18329
18357
  },
18330
18358
  {
18331
18359
  "kind": "field",
18332
- "name": "duration",
18360
+ "name": "mode",
18333
18361
  "type": {
18334
- "text": "number"
18362
+ "text": "string"
18335
18363
  },
18336
- "default": "5000"
18364
+ "default": "\"auto\""
18337
18365
  },
18338
18366
  {
18339
18367
  "kind": "field",
18340
- "name": "#list",
18368
+ "name": "theme",
18369
+ "type": {
18370
+ "text": "string"
18371
+ },
18372
+ "default": "\"\""
18373
+ },
18374
+ {
18375
+ "kind": "field",
18376
+ "name": "themes",
18377
+ "type": {
18378
+ "text": "readonly OptionItem[]"
18379
+ },
18380
+ "default": "[]"
18381
+ },
18382
+ {
18383
+ "kind": "field",
18384
+ "name": "gallery",
18385
+ "type": {
18386
+ "text": "boolean"
18387
+ },
18388
+ "default": "false"
18389
+ },
18390
+ {
18391
+ "kind": "field",
18392
+ "name": "status",
18393
+ "type": {
18394
+ "text": "string"
18395
+ },
18396
+ "default": "\"\""
18397
+ },
18398
+ {
18399
+ "kind": "field",
18400
+ "name": "label",
18401
+ "type": {
18402
+ "text": "string"
18403
+ },
18404
+ "default": "\"Theme\""
18405
+ },
18406
+ {
18407
+ "kind": "field",
18408
+ "name": "#button",
18341
18409
  "privacy": "private",
18342
18410
  "readonly": true
18343
18411
  },
18344
18412
  {
18345
18413
  "kind": "field",
18346
- "name": "#onDialogOpen",
18414
+ "name": "#mode",
18415
+ "privacy": "private",
18416
+ "readonly": true
18417
+ },
18418
+ {
18419
+ "kind": "field",
18420
+ "name": "#theme",
18421
+ "privacy": "private",
18422
+ "readonly": true
18423
+ },
18424
+ {
18425
+ "kind": "field",
18426
+ "name": "#gallery",
18427
+ "privacy": "private",
18428
+ "readonly": true
18429
+ },
18430
+ {
18431
+ "kind": "field",
18432
+ "name": "#status",
18433
+ "privacy": "private",
18434
+ "readonly": true
18435
+ },
18436
+ {
18437
+ "kind": "field",
18438
+ "name": "#file",
18439
+ "privacy": "private",
18440
+ "readonly": true
18441
+ },
18442
+ {
18443
+ "kind": "field",
18444
+ "name": "#popover",
18347
18445
  "privacy": "private",
18348
18446
  "readonly": true
18349
18447
  },
18448
+ {
18449
+ "kind": "method",
18450
+ "name": "show",
18451
+ "description": "Opens the popover under the button."
18452
+ },
18453
+ {
18454
+ "kind": "method",
18455
+ "name": "#detail",
18456
+ "privacy": "private",
18457
+ "parameters": [
18458
+ {
18459
+ "name": "type",
18460
+ "type": {
18461
+ "text": "string"
18462
+ }
18463
+ },
18464
+ {
18465
+ "name": "detail",
18466
+ "type": {
18467
+ "text": "Detail"
18468
+ }
18469
+ }
18470
+ ]
18471
+ },
18350
18472
  {
18351
18473
  "kind": "method",
18352
18474
  "name": "create",
@@ -18367,22 +18489,483 @@
18367
18489
  },
18368
18490
  {
18369
18491
  "kind": "method",
18370
- "name": "show",
18492
+ "name": "update",
18493
+ "privacy": "protected",
18371
18494
  "parameters": [
18372
18495
  {
18373
- "name": "message",
18374
- "type": {
18375
- "text": "string"
18376
- }
18377
- },
18378
- {
18379
- "name": "tone",
18380
- "default": "\"neutral\"",
18496
+ "name": "_changed",
18381
18497
  "type": {
18382
- "text": "Tone"
18498
+ "text": "ReadonlySet<string>"
18383
18499
  }
18384
18500
  }
18385
- ]
18501
+ ],
18502
+ "description": "Sets what the changed properties affect.",
18503
+ "inheritedFrom": {
18504
+ "name": "GwElement",
18505
+ "module": "src/element.ts"
18506
+ }
18507
+ },
18508
+ {
18509
+ "kind": "field",
18510
+ "name": "shadow",
18511
+ "type": {
18512
+ "text": "boolean"
18513
+ },
18514
+ "static": true,
18515
+ "default": "true",
18516
+ "description": "Whether to attach a shadow root. Light DOM elements set this false.",
18517
+ "inheritedFrom": {
18518
+ "name": "GwElement",
18519
+ "module": "src/element.ts"
18520
+ }
18521
+ },
18522
+ {
18523
+ "kind": "field",
18524
+ "name": "shadowRootOptions",
18525
+ "type": {
18526
+ "text": "ShadowRootInit"
18527
+ },
18528
+ "static": true,
18529
+ "default": "{ mode: \"open\" }",
18530
+ "description": "How the shadow root is attached.",
18531
+ "inheritedFrom": {
18532
+ "name": "GwElement",
18533
+ "module": "src/element.ts"
18534
+ }
18535
+ },
18536
+ {
18537
+ "kind": "method",
18538
+ "name": "define",
18539
+ "static": true,
18540
+ "parameters": [
18541
+ {
18542
+ "name": "tag",
18543
+ "type": {
18544
+ "text": "string"
18545
+ }
18546
+ }
18547
+ ],
18548
+ "description": "Adds the property accessors, then defines the element.",
18549
+ "inheritedFrom": {
18550
+ "name": "GwElement",
18551
+ "module": "src/element.ts"
18552
+ }
18553
+ },
18554
+ {
18555
+ "kind": "field",
18556
+ "name": "#values",
18557
+ "privacy": "private",
18558
+ "readonly": true,
18559
+ "default": "new Map<string, PropertyValue>()",
18560
+ "inheritedFrom": {
18561
+ "name": "GwElement",
18562
+ "module": "src/element.ts"
18563
+ }
18564
+ },
18565
+ {
18566
+ "kind": "field",
18567
+ "name": "#defaults",
18568
+ "privacy": "private",
18569
+ "readonly": true,
18570
+ "default": "new Map<string, PropertyValue>()",
18571
+ "inheritedFrom": {
18572
+ "name": "GwElement",
18573
+ "module": "src/element.ts"
18574
+ }
18575
+ },
18576
+ {
18577
+ "kind": "field",
18578
+ "name": "#changed",
18579
+ "privacy": "private",
18580
+ "readonly": true,
18581
+ "default": "new Set<string>()",
18582
+ "inheritedFrom": {
18583
+ "name": "GwElement",
18584
+ "module": "src/element.ts"
18585
+ }
18586
+ },
18587
+ {
18588
+ "kind": "field",
18589
+ "name": "#unreflected",
18590
+ "privacy": "private",
18591
+ "readonly": true,
18592
+ "default": "new Set<string>()",
18593
+ "inheritedFrom": {
18594
+ "name": "GwElement",
18595
+ "module": "src/element.ts"
18596
+ }
18597
+ },
18598
+ {
18599
+ "kind": "field",
18600
+ "name": "#created",
18601
+ "privacy": "private",
18602
+ "type": {
18603
+ "text": "boolean"
18604
+ },
18605
+ "default": "false",
18606
+ "inheritedFrom": {
18607
+ "name": "GwElement",
18608
+ "module": "src/element.ts"
18609
+ }
18610
+ },
18611
+ {
18612
+ "kind": "field",
18613
+ "name": "#queued",
18614
+ "privacy": "private",
18615
+ "type": {
18616
+ "text": "boolean"
18617
+ },
18618
+ "default": "false",
18619
+ "inheritedFrom": {
18620
+ "name": "GwElement",
18621
+ "module": "src/element.ts"
18622
+ }
18623
+ },
18624
+ {
18625
+ "kind": "field",
18626
+ "name": "#pending",
18627
+ "privacy": "private",
18628
+ "type": {
18629
+ "text": "Promise<void> | undefined"
18630
+ },
18631
+ "inheritedFrom": {
18632
+ "name": "GwElement",
18633
+ "module": "src/element.ts"
18634
+ }
18635
+ },
18636
+ {
18637
+ "kind": "field",
18638
+ "name": "#reflecting",
18639
+ "privacy": "private",
18640
+ "type": {
18641
+ "text": "boolean"
18642
+ },
18643
+ "default": "false",
18644
+ "inheritedFrom": {
18645
+ "name": "GwElement",
18646
+ "module": "src/element.ts"
18647
+ }
18648
+ },
18649
+ {
18650
+ "kind": "field",
18651
+ "name": "#resolveUpdated",
18652
+ "privacy": "private",
18653
+ "type": {
18654
+ "text": "() => void"
18655
+ },
18656
+ "inheritedFrom": {
18657
+ "name": "GwElement",
18658
+ "module": "src/element.ts"
18659
+ }
18660
+ },
18661
+ {
18662
+ "kind": "field",
18663
+ "name": "#updated",
18664
+ "privacy": "private",
18665
+ "readonly": true,
18666
+ "default": "new Promise<void>((resolve) => { this.#resolveUpdated = resolve; })",
18667
+ "inheritedFrom": {
18668
+ "name": "GwElement",
18669
+ "module": "src/element.ts"
18670
+ }
18671
+ },
18672
+ {
18673
+ "kind": "field",
18674
+ "name": "renderRoot",
18675
+ "type": {
18676
+ "text": "ShadowRoot | HTMLElement"
18677
+ },
18678
+ "readonly": true,
18679
+ "description": "The shadow root, or the element itself for a light DOM element.",
18680
+ "inheritedFrom": {
18681
+ "name": "GwElement",
18682
+ "module": "src/element.ts"
18683
+ }
18684
+ },
18685
+ {
18686
+ "kind": "field",
18687
+ "name": "#own",
18688
+ "privacy": "private",
18689
+ "type": {
18690
+ "text": "typeof GwElement"
18691
+ },
18692
+ "readonly": true,
18693
+ "description": "The element's own class, for its static properties and styles.",
18694
+ "default": "new.target",
18695
+ "inheritedFrom": {
18696
+ "name": "GwElement",
18697
+ "module": "src/element.ts"
18698
+ }
18699
+ },
18700
+ {
18701
+ "kind": "field",
18702
+ "name": "updateComplete",
18703
+ "description": "Resolves once the pending update has run, or the first one before it connects.",
18704
+ "readonly": true,
18705
+ "inheritedFrom": {
18706
+ "name": "GwElement",
18707
+ "module": "src/element.ts"
18708
+ }
18709
+ },
18710
+ {
18711
+ "kind": "method",
18712
+ "name": "defaultOf",
18713
+ "privacy": "protected",
18714
+ "parameters": [
18715
+ {
18716
+ "name": "name",
18717
+ "type": {
18718
+ "text": "string"
18719
+ }
18720
+ }
18721
+ ],
18722
+ "description": "The value a property returns to when its attribute is removed. Defaults\nto the value it was given in the constructor.",
18723
+ "inheritedFrom": {
18724
+ "name": "GwElement",
18725
+ "module": "src/element.ts"
18726
+ }
18727
+ },
18728
+ {
18729
+ "kind": "method",
18730
+ "name": "requestUpdate",
18731
+ "parameters": [
18732
+ {
18733
+ "name": "names",
18734
+ "type": {
18735
+ "text": "readonly string[]"
18736
+ }
18737
+ }
18738
+ ],
18739
+ "description": "Asks for an update with the given properties marked as changed.",
18740
+ "inheritedFrom": {
18741
+ "name": "GwElement",
18742
+ "module": "src/element.ts"
18743
+ }
18744
+ },
18745
+ {
18746
+ "kind": "method",
18747
+ "name": "#flush",
18748
+ "privacy": "private",
18749
+ "inheritedFrom": {
18750
+ "name": "GwElement",
18751
+ "module": "src/element.ts"
18752
+ }
18753
+ },
18754
+ {
18755
+ "kind": "method",
18756
+ "name": "#setProperty",
18757
+ "privacy": "private",
18758
+ "parameters": [
18759
+ {
18760
+ "name": "name",
18761
+ "type": {
18762
+ "text": "string"
18763
+ }
18764
+ },
18765
+ {
18766
+ "name": "options",
18767
+ "type": {
18768
+ "text": "PropertyOptions"
18769
+ }
18770
+ },
18771
+ {
18772
+ "name": "value",
18773
+ "type": {
18774
+ "text": "PropertyValue"
18775
+ }
18776
+ }
18777
+ ],
18778
+ "inheritedFrom": {
18779
+ "name": "GwElement",
18780
+ "module": "src/element.ts"
18781
+ }
18782
+ }
18783
+ ],
18784
+ "events": [
18785
+ {
18786
+ "name": "reset",
18787
+ "type": {
18788
+ "text": "Event"
18789
+ },
18790
+ "description": "When Reset is pressed."
18791
+ },
18792
+ {
18793
+ "type": {
18794
+ "text": "CustomEvent<{ mode: string }>"
18795
+ },
18796
+ "description": "When a mode is picked.",
18797
+ "name": "mode"
18798
+ },
18799
+ {
18800
+ "type": {
18801
+ "text": "CustomEvent<{ id: string }>"
18802
+ },
18803
+ "description": "When a theme is picked.",
18804
+ "name": "theme"
18805
+ },
18806
+ {
18807
+ "type": {
18808
+ "text": "CustomEvent<{ text: string, name: string }>"
18809
+ },
18810
+ "description": "When a theme file is chosen, with its text and file name.",
18811
+ "name": "import"
18812
+ }
18813
+ ],
18814
+ "attributes": [
18815
+ {
18816
+ "type": {
18817
+ "text": "\"auto\"|\"light\"|\"dark\"|\"darker\""
18818
+ },
18819
+ "description": "The mode in use. Defaults to `auto`.",
18820
+ "name": "mode"
18821
+ },
18822
+ {
18823
+ "type": {
18824
+ "text": "string"
18825
+ },
18826
+ "description": "The theme in use, by id.",
18827
+ "name": "theme"
18828
+ },
18829
+ {
18830
+ "type": {
18831
+ "text": "OptionItem[]"
18832
+ },
18833
+ "description": "The themes to offer, as JSON. The select hides with fewer than two. With `gallery`, a `group` gathers a family's themes.",
18834
+ "name": "themes"
18835
+ },
18836
+ {
18837
+ "type": {
18838
+ "text": "boolean"
18839
+ },
18840
+ "description": "Shows the themes as preview cards rather than a select.",
18841
+ "name": "gallery"
18842
+ },
18843
+ {
18844
+ "type": {
18845
+ "text": "string"
18846
+ },
18847
+ "description": "A line under the controls, such as an import's result.",
18848
+ "name": "status"
18849
+ },
18850
+ {
18851
+ "type": {
18852
+ "text": "string"
18853
+ },
18854
+ "description": "The button's accessible name and the popover's heading. Defaults to `Theme`.",
18855
+ "name": "label"
18856
+ }
18857
+ ],
18858
+ "superclass": {
18859
+ "name": "GwElement",
18860
+ "module": "/src/element.js"
18861
+ },
18862
+ "tagName": "gw-theme-picker",
18863
+ "customElement": true,
18864
+ "summary": "A button opening the page's mode, theme and import."
18865
+ }
18866
+ ],
18867
+ "exports": [
18868
+ {
18869
+ "kind": "js",
18870
+ "name": "GwThemePicker",
18871
+ "declaration": {
18872
+ "name": "GwThemePicker",
18873
+ "module": "src/gw-theme-picker.ts"
18874
+ }
18875
+ }
18876
+ ]
18877
+ },
18878
+ {
18879
+ "kind": "javascript-module",
18880
+ "path": "src/gw-toast.ts",
18881
+ "declarations": [
18882
+ {
18883
+ "kind": "class",
18884
+ "description": "Where toasts appear: the bottom corner on the end side, away from what\npeople click. Call `show(message, tone)`; each toast is announced politely\nand fades out after `duration` milliseconds.\n\nA toast only tells; it has no actions and lets every click through, since\nit may sit over something interactive and leaves before it can be used.\nIt's in the top layer and rises above any dialog each time one shows. It's\na last resort: show an outcome where it happened instead.",
18885
+ "name": "GwToaster",
18886
+ "members": [
18887
+ {
18888
+ "kind": "field",
18889
+ "name": "properties",
18890
+ "type": {
18891
+ "text": "Properties"
18892
+ },
18893
+ "static": true,
18894
+ "default": "{ duration: { type: \"number\" }, }",
18895
+ "inheritedFrom": {
18896
+ "name": "GwElement",
18897
+ "module": "src/element.ts"
18898
+ }
18899
+ },
18900
+ {
18901
+ "kind": "field",
18902
+ "name": "styles",
18903
+ "type": {
18904
+ "text": "readonly CSSStyleSheet[]"
18905
+ },
18906
+ "static": true,
18907
+ "default": "[ base, css` :host { position: fixed; inset: auto var(--gw-space-4) var(--gw-space-4) auto; width: min(22rem, calc(100vw - 2 * var(--gw-space-4))); padding: 0; margin: 0; overflow: visible; color: inherit; pointer-events: none; user-select: none; background: none; border: 0; } :host(:dir(rtl)) { inset: auto auto var(--gw-space-4) var(--gw-space-4); } :host(:not(:popover-open)) { display: none; } .list { display: flex; flex-direction: column; gap: var(--gw-space-1); align-items: flex-end; } .toast { max-width: 100%; padding: var(--gw-space-2) var(--gw-space-3); font-size: var(--gw-font-size-s); color: var(--gw-color-text-strong); background: var(--gw-color-surface-overlay); border: var(--gw-border-width) solid var(--gw-color-border-normal); border-inline-start: calc(var(--gw-border-width) * 4) solid var(--gw-toast-tone); border-radius: var(--gw-radius-control); box-shadow: var(--gw-shadow-m); } `, ]",
18908
+ "inheritedFrom": {
18909
+ "name": "GwElement",
18910
+ "module": "src/element.ts"
18911
+ }
18912
+ },
18913
+ {
18914
+ "kind": "field",
18915
+ "name": "duration",
18916
+ "type": {
18917
+ "text": "number"
18918
+ },
18919
+ "default": "5000"
18920
+ },
18921
+ {
18922
+ "kind": "field",
18923
+ "name": "#list",
18924
+ "privacy": "private",
18925
+ "readonly": true
18926
+ },
18927
+ {
18928
+ "kind": "field",
18929
+ "name": "#onDialogOpen",
18930
+ "privacy": "private",
18931
+ "readonly": true
18932
+ },
18933
+ {
18934
+ "kind": "method",
18935
+ "name": "create",
18936
+ "privacy": "protected",
18937
+ "parameters": [
18938
+ {
18939
+ "name": "root",
18940
+ "type": {
18941
+ "text": "ShadowRoot"
18942
+ }
18943
+ }
18944
+ ],
18945
+ "description": "Builds the shadow root's content once, on first connection.",
18946
+ "inheritedFrom": {
18947
+ "name": "GwElement",
18948
+ "module": "src/element.ts"
18949
+ }
18950
+ },
18951
+ {
18952
+ "kind": "method",
18953
+ "name": "show",
18954
+ "parameters": [
18955
+ {
18956
+ "name": "message",
18957
+ "type": {
18958
+ "text": "string"
18959
+ }
18960
+ },
18961
+ {
18962
+ "name": "tone",
18963
+ "default": "\"neutral\"",
18964
+ "type": {
18965
+ "text": "Tone"
18966
+ }
18967
+ }
18968
+ ]
18386
18969
  },
18387
18970
  {
18388
18971
  "kind": "method",
@@ -19006,6 +19589,14 @@
19006
19589
  "module": "src/gw-spinner.js"
19007
19590
  }
19008
19591
  },
19592
+ {
19593
+ "kind": "js",
19594
+ "name": "*",
19595
+ "declaration": {
19596
+ "name": "*",
19597
+ "module": "src/gw-theme-gallery.js"
19598
+ }
19599
+ },
19009
19600
  {
19010
19601
  "kind": "js",
19011
19602
  "name": "*",