@threadlabs/looma 0.37.0 → 0.37.1

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.
Files changed (162) hide show
  1. package/components/shared/icons.js +3 -0
  2. package/components/ui-button/ui-button.html +3 -12
  3. package/components/ui-card/ui-card.html +5 -5
  4. package/components/ui-checkbox/ui-checkbox.html +0 -6
  5. package/components/ui-color-picker/ui-color-picker.html +0 -9
  6. package/components/ui-combobox/ui-combobox.html +1 -13
  7. package/components/ui-cycle-button/ui-cycle-button.html +41 -0
  8. package/components/ui-cycle-button/ui-cycle-button.js +19 -0
  9. package/components/ui-dialog/ui-dialog.html +1 -1
  10. package/components/ui-icon/ui-icon.html +3 -0
  11. package/components/ui-icon-button/ui-icon-button.html +10 -14
  12. package/components/ui-input/ui-input.html +1 -16
  13. package/components/ui-input-group/ui-input-group.html +0 -10
  14. package/components/ui-menu/ui-menu.html +1 -1
  15. package/components/ui-popover/ui-popover.html +1 -1
  16. package/components/ui-radio/ui-radio.html +0 -6
  17. package/components/ui-select/ui-select.html +2 -8
  18. package/components/ui-switch/ui-switch.html +0 -6
  19. package/components/ui-tooltip/ui-tooltip.html +1 -1
  20. package/dist/index.js +47 -46
  21. package/docs/README.md +45 -6
  22. package/docs/card.html +2 -1
  23. package/docs/catalog.json +212 -37
  24. package/docs/customizer-render.mjs +7 -6
  25. package/docs/customizer.js +13 -19
  26. package/docs/theme.mjs +3 -3
  27. package/editor/icons.d.ts +3 -0
  28. package/editor/index.js +4 -1
  29. package/package.json +2 -2
  30. package/styles/ui-button.css +2 -14
  31. package/styles/ui-card.css +1 -1
  32. package/styles/ui-checkbox.css +0 -9
  33. package/styles/ui-color-picker.css +0 -13
  34. package/styles/ui-combobox.css +2 -28
  35. package/styles/ui-cycle-button.css +36 -0
  36. package/styles/ui-dialog.css +2 -2
  37. package/styles/ui-icon-button.css +6 -13
  38. package/styles/ui-input-group.css +0 -13
  39. package/styles/ui-input.css +2 -18
  40. package/styles/ui-menu.css +1 -1
  41. package/styles/ui-popover.css +1 -1
  42. package/styles/ui-radio.css +0 -9
  43. package/styles/ui-select.css +3 -10
  44. package/styles/ui-switch.css +0 -9
  45. package/styles/ui-tooltip.css +1 -1
  46. package/theme-system.css +14 -14
  47. package/tokens.css +2 -10
  48. package/vanilla/UiCycleButton.d.ts +29 -0
  49. package/vanilla/UiCycleButton.js +85 -0
  50. package/vanilla/UiIcon.js +1 -1
  51. package/vanilla/index.js +1 -0
  52. package/vue/UiButton.vue +2 -11
  53. package/vue/UiCard.vue +5 -3
  54. package/vue/UiCheckbox.vue +0 -6
  55. package/vue/UiColorPicker.vue +0 -9
  56. package/vue/UiCombobox.vue +2 -26
  57. package/vue/UiCycleButton.d.ts +69 -0
  58. package/vue/UiCycleButton.js +2 -0
  59. package/vue/UiCycleButton.vue +403 -0
  60. package/vue/UiDialog.vue +6 -2
  61. package/vue/UiIcon.vue +22 -0
  62. package/vue/UiIconButton.vue +2 -16
  63. package/vue/UiInput.vue +1 -22
  64. package/vue/UiInputGroup.vue +0 -10
  65. package/vue/UiMenu.vue +3 -1
  66. package/vue/UiPopover.vue +3 -1
  67. package/vue/UiRadio.vue +0 -6
  68. package/vue/UiSelect.vue +2 -8
  69. package/vue/UiSwitch.vue +0 -6
  70. package/vue/UiTooltip.vue +3 -1
  71. package/vue/chunks/UiAffordanceScope.js +1 -1
  72. package/vue/chunks/UiAvatar.js +1 -1
  73. package/vue/chunks/UiAvatarGroup.js +1 -1
  74. package/vue/chunks/UiBadge.js +1 -1
  75. package/vue/chunks/UiBreadcrumbItem.js +1 -1
  76. package/vue/chunks/UiBreadcrumbs.js +1 -1
  77. package/vue/chunks/UiButton.js +3 -3
  78. package/vue/chunks/UiCallout.js +1 -1
  79. package/vue/chunks/UiCard.js +4 -4
  80. package/vue/chunks/UiCheckbox.js +2 -2
  81. package/vue/chunks/UiCluster.js +1 -1
  82. package/vue/chunks/UiColorPicker.js +2 -2
  83. package/vue/chunks/UiCombobox.js +2 -2
  84. package/vue/chunks/UiContainer.js +1 -1
  85. package/vue/chunks/UiContextMenu.js +1 -1
  86. package/vue/chunks/UiCover.js +1 -1
  87. package/vue/chunks/UiCurveEditor.js +1 -1
  88. package/vue/chunks/UiCycleButton.js +352 -0
  89. package/vue/chunks/UiDescriptionItem.js +1 -1
  90. package/vue/chunks/UiDescriptionList.js +1 -1
  91. package/vue/chunks/UiDialog.js +2 -2
  92. package/vue/chunks/UiDisclosure.js +1 -1
  93. package/vue/chunks/UiEditable.js +1 -1
  94. package/vue/chunks/UiEditorBlockActions.js +1 -1
  95. package/vue/chunks/UiEditorChipEditor.js +1 -1
  96. package/vue/chunks/UiEditorCodeLanguage.js +1 -1
  97. package/vue/chunks/UiEditorFootnoteEditor.js +1 -1
  98. package/vue/chunks/UiEditorImageToolbar.js +1 -1
  99. package/vue/chunks/UiEditorInsertTableGrid.js +1 -1
  100. package/vue/chunks/UiEditorLinkCard.js +1 -1
  101. package/vue/chunks/UiEditorLinkForm.js +1 -1
  102. package/vue/chunks/UiEditorMentionMenu.js +1 -1
  103. package/vue/chunks/UiEditorMentionMenuItem.js +1 -1
  104. package/vue/chunks/UiEditorSlashMenu.js +1 -1
  105. package/vue/chunks/UiEditorSlashMenuGroup.js +1 -1
  106. package/vue/chunks/UiEditorSlashMenuItem.js +1 -1
  107. package/vue/chunks/UiEditorSurface.js +1 -1
  108. package/vue/chunks/UiEditorTableContextMenu.js +1 -1
  109. package/vue/chunks/UiEditorTableOverlay.js +1 -1
  110. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  111. package/vue/chunks/UiEditorToolbar.js +1 -1
  112. package/vue/chunks/UiFloatingActionButton.js +1 -1
  113. package/vue/chunks/UiFormField.js +1 -1
  114. package/vue/chunks/UiGrid.js +1 -1
  115. package/vue/chunks/UiIcon.js +70 -2
  116. package/vue/chunks/UiIconButton.js +4 -4
  117. package/vue/chunks/UiImage.js +1 -1
  118. package/vue/chunks/UiInput.js +2 -2
  119. package/vue/chunks/UiInputGroup.js +2 -2
  120. package/vue/chunks/UiLightEditor.js +1 -1
  121. package/vue/chunks/UiList.js +1 -1
  122. package/vue/chunks/UiListItem.js +1 -1
  123. package/vue/chunks/UiListbox.js +1 -1
  124. package/vue/chunks/UiMenu.js +2 -2
  125. package/vue/chunks/UiMenuGroup.js +1 -1
  126. package/vue/chunks/UiMenuItem.js +1 -1
  127. package/vue/chunks/UiMeter.js +1 -1
  128. package/vue/chunks/UiNavItem.js +1 -1
  129. package/vue/chunks/UiNumberInput.js +1 -1
  130. package/vue/chunks/UiPageHeader.js +1 -1
  131. package/vue/chunks/UiPopover.js +2 -2
  132. package/vue/chunks/UiRadio.js +2 -2
  133. package/vue/chunks/UiRadioGroup.js +1 -1
  134. package/vue/chunks/UiReel.js +1 -1
  135. package/vue/chunks/UiScrollArea.js +1 -1
  136. package/vue/chunks/UiSearchResultRow.js +1 -1
  137. package/vue/chunks/UiSearchShell.js +1 -1
  138. package/vue/chunks/UiSection.js +1 -1
  139. package/vue/chunks/UiSelect.js +2 -2
  140. package/vue/chunks/UiSeparator.js +1 -1
  141. package/vue/chunks/UiSidebar.js +1 -1
  142. package/vue/chunks/UiSlider.js +1 -1
  143. package/vue/chunks/UiSpinner.js +1 -1
  144. package/vue/chunks/UiStack.js +1 -1
  145. package/vue/chunks/UiStatusMessage.js +1 -1
  146. package/vue/chunks/UiSwatch.js +1 -1
  147. package/vue/chunks/UiSwitch.js +2 -2
  148. package/vue/chunks/UiSwitcher.js +1 -1
  149. package/vue/chunks/UiTable.js +1 -1
  150. package/vue/chunks/UiTabs.js +1 -1
  151. package/vue/chunks/UiText.js +1 -1
  152. package/vue/chunks/UiTextarea.js +1 -1
  153. package/vue/chunks/UiToast.js +1 -1
  154. package/vue/chunks/UiToastRegion.js +1 -1
  155. package/vue/chunks/UiTooltip.js +2 -2
  156. package/vue/chunks/UiTree.js +1 -1
  157. package/vue/chunks/UiTreeItem.js +1 -1
  158. package/vue/chunks/props.js +12 -1
  159. package/vue/components.css +74 -179
  160. package/vue/editor/index.js +68 -0
  161. package/vue/index.d.ts +1 -0
  162. package/vue/index.js +2 -1
@@ -46,6 +46,8 @@ export const icons = {
46
46
  "merge": [["path",{"d":"m8 6 4-4 4 4"}],["path",{"d":"M12 2v10.3a4 4 0 0 1-1.172 2.872L4 22"}],["path",{"d":"m20 22-5-5"}]],
47
47
  "message-square-warning": [["path",{"d":"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"}],["path",{"d":"M12 15h.01"}],["path",{"d":"M12 7v4"}]],
48
48
  "minus": [["path",{"d":"M5 12h14"}]],
49
+ "monitor": [["rect",{"width":"20","height":"14","x":"2","y":"3","rx":"2"}],["line",{"x1":"8","x2":"16","y1":"21","y2":"21"}],["line",{"x1":"12","x2":"12","y1":"17","y2":"21"}]],
50
+ "moon": [["path",{"d":"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"}]],
49
51
  "notebook-pen": [["path",{"d":"M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4"}],["path",{"d":"M2 6h4"}],["path",{"d":"M2 10h4"}],["path",{"d":"M2 14h4"}],["path",{"d":"M2 18h4"}],["path",{"d":"M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z"}]],
50
52
  "paint-bucket": [["path",{"d":"m19 11-8-8-8.6 8.6a2 2 0 0 0 0 2.8l5.2 5.2c.8.8 2 .8 2.8 0L19 11Z"}],["path",{"d":"m5 2 5 5"}],["path",{"d":"M2 13h15"}],["path",{"d":"M22 20a2 2 0 1 1-4 0c0-1.6 1.7-2.4 2-4 .3 1.6 2 2.4 2 4Z"}]],
51
53
  "panel-bottom": [["rect",{"width":"18","height":"18","x":"3","y":"3","rx":"2"}],["path",{"d":"M3 15h18"}]],
@@ -64,6 +66,7 @@ export const icons = {
64
66
  "settings": [["path",{"d":"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"}],["circle",{"cx":"12","cy":"12","r":"3"}]],
65
67
  "split": [["path",{"d":"M16 3h5v5"}],["path",{"d":"M8 3H3v5"}],["path",{"d":"M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3"}],["path",{"d":"m15 9 6-6"}]],
66
68
  "strikethrough": [["path",{"d":"M16 4H9a3 3 0 0 0-2.83 4"}],["path",{"d":"M14 12a4 4 0 0 1 0 8H6"}],["line",{"x1":"4","x2":"20","y1":"12","y2":"12"}]],
69
+ "sun": [["circle",{"cx":"12","cy":"12","r":"4"}],["path",{"d":"M12 2v2"}],["path",{"d":"M12 20v2"}],["path",{"d":"m4.93 4.93 1.41 1.41"}],["path",{"d":"m17.66 17.66 1.41 1.41"}],["path",{"d":"M2 12h2"}],["path",{"d":"M20 12h2"}],["path",{"d":"m6.34 17.66-1.41 1.41"}],["path",{"d":"m19.07 4.93-1.41 1.41"}]],
67
70
  "superscript": [["path",{"d":"m4 19 8-8"}],["path",{"d":"m12 19-8-8"}],["path",{"d":"M20 12h-4c0-1.5.442-2 1.5-2.5S20 8.334 20 7.002c0-.472-.17-.93-.484-1.29a2.105 2.105 0 0 0-2.617-.436c-.42.239-.738.614-.899 1.06"}]],
68
71
  "table": [["path",{"d":"M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18"}]],
69
72
  "tag": [["path",{"d":"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"}],["circle",{"cx":"7.5","cy":"7.5","r":".5","fill":"currentColor"}]],
@@ -17,8 +17,8 @@
17
17
  quiet outline, neutral text and slightly raised surface, independently of action tone.</prop>
18
18
  <prop name="size" type="keyword" values="xs, sm, md, lg" default="md"
19
19
  >Height, padding, and type size. xs is 1.5rem with the smallest text, for a control inside a line of small text; sm is the small control height (2rem by
20
- default) with tighter padding and smaller text, md is the standard control height (2.5rem), and lg is taller (3rem) with roomier padding. Under touch, sm
21
- grows to the touch minimum, while xs keeps its size inside its line and gains an invisible touch-sized hit area.</prop>
20
+ default) with tighter padding and smaller text, md is the standard control height (2.5rem), and lg is taller (3rem) with roomier padding. Visible sizes
21
+ stay the same on touch. Inline xs and link actions can gain an adjustable invisible hit area.</prop>
22
22
  <prop name="shape" type="keyword" values="rounded, pill" default="rounded"
23
23
  >rounded uses the theme's action radius; pill rounds the ends fully, for a compact choice such as a status or a person.</prop>
24
24
  <prop name="tone" type="keyword" values="accent, neutral, danger, success, warning, info" default="accent"
@@ -555,18 +555,9 @@
555
555
  }
556
556
 
557
557
  /* The size states outrank :host, so sm is named too, or a small button would stay small. */
558
- @media (pointer: coarse) {
559
- :host {
560
- min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
561
- }
562
- :host([size="sm"]) {
563
- min-block-size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
564
- }
565
- }
566
558
 
567
559
  /* Under touch, a link-style button's press lands within the control minimum: an invisible hit
568
- area, centred on it, like IconButton's. A boxed button grows to the minimum itself (below);
569
- a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
560
+ area, centred on it, like IconButton's. A link-style action keeps its text size, so a standalone one ("See all" under a list) needs the
570
561
  area. xs sits inside a line of text the same way, so it keeps its size and gains the area too.
571
562
  Only these need it: a hit area on every button would reach over its neighbours. */
572
563
  html[data-ui-input-modality="touch"] :host[data-appearance="link"],
@@ -6,13 +6,13 @@
6
6
  >The surface. outlined is a bordered panel on the page; subtle is a quiet filled one with no border, for supporting details set apart from the flow;
7
7
  elevated adds a subtle lift above the page, for a view's one card, such as sign-in. Treatment independently controls decorative material.</prop>
8
8
  <prop name="treatment" type="keyword" values="standard, expressive" default="standard"
9
- >How much of the theme's decorative material the surface expresses. standard preserves its restrained treatment; expressive uses the full material treatment.
10
- This does not add elevation or require glass.</prop>
9
+ >How much of the theme's decorative material the surface expresses. standard preserves its restrained treatment; expressive uses the full material
10
+ treatment. This does not add elevation or require glass.</prop>
11
11
  <prop name="padding" type="keyword" values="xs, sm, md, lg" default="md"
12
12
  >The space inside the card: xs is compact (0.5rem), sm is snug (0.75rem), md is the default (1.5rem), and lg is roomy (2rem).</prop>
13
13
  <prop name="tone" type="keyword" values="neutral, accent, info, success, warning, danger" default="neutral"
14
- >accent, info, success, warning and danger add a quiet semantic surface without changing card geometry. Row highlights follow the
15
- surface hue; action controls retain their own intent.</prop>
14
+ >accent, info, success, warning and danger add a quiet semantic surface without changing card geometry. Row highlights follow the surface hue; action
15
+ controls retain their own intent.</prop>
16
16
  <prop name="as" type="keyword" values="div, section, article, aside" default="div"
17
17
  >The native element the card renders. Choose the one that names the content: a section of a page, a self-contained article, or an aside.</prop>
18
18
  </defs>
@@ -68,7 +68,7 @@
68
68
  }
69
69
 
70
70
  :host([treatment="expressive"]) {
71
- --_ui-panel-glass: clamp(0, var(--ui-glassiness, 0), 1);
71
+ --_ui-panel-glass: calc(clamp(0, var(--ui-glassiness, 0), 1) + 2 * pow(clamp(0, var(--ui-glassiness, 0), 1), 4));
72
72
  --_ui-panel-separation: clamp(0, var(--ui-surface-separation, 0), 1);
73
73
  --_ui-panel-rim: calc((var(--_ui-panel-separation) + var(--_ui-panel-glass) * 0.25) * 0.65 * 8px);
74
74
  border-width: calc(var(--ui-border-width) + var(--_ui-panel-rim));
@@ -249,12 +249,6 @@
249
249
  padding-block: max(0px, calc((var(--_row) - max(var(--_line), var(--_ui-checkbox-size, 1.125rem))) / 2)) !important;
250
250
  }
251
251
 
252
- @media (pointer: coarse) {
253
- :host([size="sm"]) {
254
- --_row: var(--ui-control-min-block-size);
255
- }
256
- }
257
-
258
252
  /* A component that sets its display still honours the hidden attribute on its root. */
259
253
  :host[hidden] {
260
254
  display: none !important;
@@ -122,14 +122,5 @@
122
122
  padding: 0 !important;
123
123
  accent-color: var(--ui-accent-solid);
124
124
  }
125
- @media (pointer: coarse) {
126
- :host {
127
- --_size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
128
- }
129
- :host([size="sm"]) {
130
- --_size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
131
- --_font: var(--ui-font-size-md);
132
- }
133
- }
134
125
  </style>
135
126
  </template>
@@ -872,20 +872,8 @@
872
872
  white-space: nowrap;
873
873
  }
874
874
  @media (pointer: coarse) {
875
- :host {
876
- --_row: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
877
- }
878
- button {
879
- min-inline-size: 2.75rem;
880
- min-block-size: calc(var(--_row) - 2 * var(--ui-border-width));
881
- }
882
- /* Under touch a small field is still a touch-sized target, as a small button is, and keeps
883
- body-size text: below 16px, iOS zooms the page into the focused field. */
884
- :host([size="sm"]) {
885
- --_row: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
886
- }
887
875
  :host([size="sm"]) input {
888
- font-size: inherit;
876
+ font-size: var(--ui-font-size-md);
889
877
  }
890
878
  }
891
879
  @media (forced-colors: active) {
@@ -0,0 +1,41 @@
1
+ <link rel="component" href="../ui-icon-button/ui-icon-button.html">
2
+ <link rel="component" href="../ui-icon/ui-icon.html">
3
+ <template component="ui-cycle-button" module="./ui-cycle-button.js">
4
+ <defs>
5
+ <prop name="items" type="list(object({ value: string, label: string, icon: string }))" required
6
+ >Ordered states with a value, readable label and Looma icon name. Activation advances to the next state and wraps.</prop>
7
+ <prop name="index" type="number" default="0">Initial or externally selected zero-based state. The first state is the default.</prop>
8
+ <prop name="label" type="string" default="State">What the button changes, such as Appearance. The selected state is included in its accessible name.</prop>
9
+ <prop name="size" type="keyword" values="sm, md, lg" default="md">Uses IconButton's compact visible sizes and adjustable invisible touch area.</prop>
10
+ <prop name="variant" type="keyword" values="ghost, outline, solid" default="outline">Uses IconButton's standard emphasis.</prop>
11
+ <prop name="disabled" type="boolean" default="false">Prevents cycling while keeping the selected state visible.</prop>
12
+ <state name="current" type="number" from="$index"></state>
13
+ <computed name="selected" from="default($items[default($current, 0)], $items[0])"></computed>
14
+ <event name="change" type="object"><prop name="value" type="string" required></prop><prop name="index" type="number" required></prop></event>
15
+ </defs>
16
+ <span><ui-icon-button
17
+ from:label="concat($label, ': ', default($selected.label, 'No choices'))"
18
+ from:title="concat($label, ': ', default($selected.label, 'No choices'))"
19
+ from:size="$size"
20
+ from:variant="$variant"
21
+ from:disabled="$disabled or $items.length &lt; 2"
22
+ tone="neutral"
23
+ aria-description="Activate to choose the next state."
24
+ >
25
+ <ui-icon from:name="default($selected.icon, '')"></ui-icon>
26
+ </ui-icon-button></span>
27
+ <style>
28
+ :host {
29
+ display: inline-flex !important;
30
+ align-items: center !important;
31
+ justify-content: center !important;
32
+ gap: 0 !important;
33
+ margin: 0 !important;
34
+ padding: 0 !important;
35
+ vertical-align: middle;
36
+ }
37
+ :host[hidden] {
38
+ display: none !important;
39
+ }
40
+ </style>
41
+ </template>
@@ -0,0 +1,19 @@
1
+ /** Cycle an ordered choice without replacing its native button or moving focus. */
2
+ export function connect(host) {
3
+ let external;
4
+ const stop = host.effect(() => {
5
+ const signature = JSON.stringify([host.props.items.value, host.props.index.value]);
6
+ if (signature === external) return;
7
+ external = signature;
8
+ const index = Math.trunc(Number(host.props.index.value));
9
+ host.state.current = Number.isFinite(index) && index >= 0 && index < host.props.items.value.length ? index : 0;
10
+ });
11
+ const cycle = () => {
12
+ const items = host.props.items.value;
13
+ if (host.props.disabled.value || items.length < 2) return;
14
+ host.state.current = (host.state.current + 1) % items.length;
15
+ host.dispatch('change', { value: items[host.state.current].value, index: host.state.current });
16
+ };
17
+ host.element.addEventListener('click', cycle);
18
+ return () => { stop(); host.element.removeEventListener('click', cycle); };
19
+ }
@@ -112,7 +112,7 @@
112
112
  /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
113
113
  transparency, saturation and edge light belong to the surrounding decorative material. */
114
114
  :host {
115
- --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
115
+ --_ui-material-glassiness: calc(clamp(0, var(--ui-glassiness, 0), 1) + 2 * pow(clamp(0, var(--ui-glassiness, 0), 1), 4));
116
116
  --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
117
117
  --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
118
118
  --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 1) * 8px);
@@ -55,6 +55,8 @@
55
55
  'merge': [{ tag: 'path', d: 'm8 6 4-4 4 4' }, { tag: 'path', d: 'M12 2v10.3a4 4 0 0 1-1.172 2.872L4 22' }, { tag: 'path', d: 'm20 22-5-5' }],
56
56
  'message-square-warning': [{ tag: 'path', d: 'M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z' }, { tag: 'path', d: 'M12 15h.01' }, { tag: 'path', d: 'M12 7v4' }],
57
57
  'minus': [{ tag: 'path', d: 'M5 12h14' }],
58
+ 'monitor': [{ tag: 'rect', width: '20', height: '14', x: '2', y: '3', rx: '2' }, { tag: 'line', x1: '8', x2: '16', y1: '21', y2: '21' }, { tag: 'line', x1: '12', x2: '12', y1: '17', y2: '21' }],
59
+ 'moon': [{ tag: 'path', d: 'M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401' }],
58
60
  'notebook-pen': [{ tag: 'path', d: 'M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4' }, { tag: 'path', d: 'M2 6h4' }, { tag: 'path', d: 'M2 10h4' }, { tag: 'path', d: 'M2 14h4' }, { tag: 'path', d: 'M2 18h4' }, { tag: 'path', d: 'M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z' }],
59
61
  'paint-bucket': [{ tag: 'path', d: 'm19 11-8-8-8.6 8.6a2 2 0 0 0 0 2.8l5.2 5.2c.8.8 2 .8 2.8 0L19 11Z' }, { tag: 'path', d: 'm5 2 5 5' }, { tag: 'path', d: 'M2 13h15' }, { tag: 'path', d: 'M22 20a2 2 0 1 1-4 0c0-1.6 1.7-2.4 2-4 .3 1.6 2 2.4 2 4Z' }],
60
62
  'panel-bottom': [{ tag: 'rect', width: '18', height: '18', x: '3', y: '3', rx: '2' }, { tag: 'path', d: 'M3 15h18' }],
@@ -73,6 +75,7 @@
73
75
  'settings': [{ tag: 'path', d: 'M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915' }, { tag: 'circle', cx: '12', cy: '12', r: '3' }],
74
76
  'split': [{ tag: 'path', d: 'M16 3h5v5' }, { tag: 'path', d: 'M8 3H3v5' }, { tag: 'path', d: 'M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3' }, { tag: 'path', d: 'm15 9 6-6' }],
75
77
  'strikethrough': [{ tag: 'path', d: 'M16 4H9a3 3 0 0 0-2.83 4' }, { tag: 'path', d: 'M14 12a4 4 0 0 1 0 8H6' }, { tag: 'line', x1: '4', x2: '20', y1: '12', y2: '12' }],
78
+ 'sun': [{ tag: 'circle', cx: '12', cy: '12', r: '4' }, { tag: 'path', d: 'M12 2v2' }, { tag: 'path', d: 'M12 20v2' }, { tag: 'path', d: 'm4.93 4.93 1.41 1.41' }, { tag: 'path', d: 'm17.66 17.66 1.41 1.41' }, { tag: 'path', d: 'M2 12h2' }, { tag: 'path', d: 'M20 12h2' }, { tag: 'path', d: 'm6.34 17.66-1.41 1.41' }, { tag: 'path', d: 'm19.07 4.93-1.41 1.41' }],
76
79
  'superscript': [{ tag: 'path', d: 'm4 19 8-8' }, { tag: 'path', d: 'm12 19-8-8' }, { tag: 'path', d: 'M20 12h-4c0-1.5.442-2 1.5-2.5S20 8.334 20 7.002c0-.472-.17-.93-.484-1.29a2.105 2.105 0 0 0-2.617-.436c-.42.239-.738.614-.899 1.06' }],
77
80
  'table': [{ tag: 'path', d: 'M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18' }],
78
81
  'tag': [{ tag: 'path', d: 'M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z' }, { tag: 'circle', cx: '7.5', cy: '7.5', r: '.5', fill: 'currentColor' }],
@@ -15,11 +15,11 @@
15
15
  <prop name="pending" type="boolean" default="false">Deprecated alias for loading.</prop>
16
16
  <prop name="label" type="string">Accessible name for the icon.</prop>
17
17
  <prop name="size" type="keyword" values="sm, md, lg" default="md"
18
- >Button and icon size together: sm is 1.75rem with a small icon, md is 2rem, and lg is 2.5rem with a large icon. On touch, every size gets an invisible hit
19
- area of at least 44px.</prop>
18
+ >Button and icon size together: sm is 1.75rem with a small icon, md is 2rem, and lg is 2.5rem with a large icon. Touch can use an invisible hit area sized
19
+ by the adjustable control target preference.</prop>
20
20
  <prop name="matchButton" type="boolean" default="false"
21
- >Matches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row's height, including
22
- touch-sized controls. Leave it off for compact toolbar and inline icon buttons.</prop>
21
+ >Matches a boxed Button of the same size when the two share a flex row. Uses the control-size theme tokens and stretches to the row's height, on mouse and
22
+ touch alike. Leave it off for compact toolbar and inline icon buttons.</prop>
23
23
  <prop name="variant" type="keyword" values="ghost, outline, solid" default="ghost"
24
24
  >Emphasis. ghost shows only the icon until it is hovered, for toolbars and dense rows; outline adds a border on the default surface; solid fills with the
25
25
  accent colour, for the one primary action in a group.</prop>
@@ -376,14 +376,6 @@
376
376
  --_size: var(--ui-control-size-lg);
377
377
  }
378
378
 
379
- @media (pointer: coarse) {
380
- :host([matchButton]) {
381
- inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
382
- min-inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
383
- min-block-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
384
- }
385
- }
386
-
387
379
  :host([round]) {
388
380
  border-radius: var(--ui-radius-round);
389
381
  }
@@ -393,14 +385,18 @@
393
385
  background-color: var(--ui-icon-button-outline-surface, var(--_icon-button-outline-surface, var(--ui-surface-default)));
394
386
  background-image: var(--ui-surface-highlight, none);
395
387
  color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
396
- box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow)), var(--_tone-glow);
388
+ box-shadow:
389
+ var(--ui-action-shadow, var(--_ui-action-shadow)),
390
+ var(--_tone-glow);
397
391
  }
398
392
 
399
393
  :host[data-appearance="solid"] {
400
394
  background-color: var(--ui-icon-button-solid-surface, var(--_icon-button-solid-surface, var(--ui-accent-solid)));
401
395
  background-image: var(--_tone-highlight);
402
396
  color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
403
- box-shadow: var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))), var(--_tone-glow);
397
+ box-shadow:
398
+ var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
399
+ var(--_tone-glow);
404
400
  }
405
401
 
406
402
  :host:hover:enabled:not([aria-disabled="true"]) {
@@ -133,28 +133,13 @@
133
133
  font-size: var(--ui-font-size-md);
134
134
  }
135
135
 
136
- /* Under touch a small field is still a touch-sized target, as a small button is, and keeps
137
- body-size text: below 16px, iOS zooms the page into the focused field. */
136
+ /* Touch may use body-size text in a small native field to avoid focus zoom; this does not impose a larger visible control height. */
138
137
  @media (pointer: coarse) {
139
- :host {
140
- min-block-size: var(
141
- --ui-input-min-block-size,
142
- var(--_ui-default-input-min-block-size, max(var(--ui-control-size-md), var(--ui-control-min-block-size)))
143
- );
144
- }
145
-
146
138
  :host,
147
139
  :host([size="sm"]),
148
140
  :host([size="lg"]) {
149
141
  font-size: var(--ui-font-size-md);
150
142
  }
151
-
152
- :host([size="sm"]) {
153
- min-block-size: var(
154
- --ui-input-min-block-size,
155
- var(--_ui-default-input-min-block-size, max(var(--ui-control-size-sm), var(--ui-control-min-block-size)))
156
- );
157
- }
158
143
  }
159
144
 
160
145
  /* Tabbing into a field selects its text; tint that selection softly instead of the page highlight. */
@@ -100,16 +100,6 @@
100
100
  min-block-size: var(--ui-control-size-lg);
101
101
  }
102
102
 
103
- @media (pointer: coarse) {
104
- :host {
105
- min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
106
- }
107
-
108
- :host:has(.field [data-ui-input-state~="size=sm"]) {
109
- min-block-size: var(--ui-control-min-block-size);
110
- }
111
- }
112
-
113
103
  :host:hover:not(:has(:is(input, textarea):focus, :is(input, textarea):disabled, :is(input, textarea):read-only, [aria-invalid="true"], :user-invalid)) {
114
104
  border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
115
105
  }
@@ -129,7 +129,7 @@
129
129
  /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
130
130
  transparency, saturation and edge light belong to the surrounding decorative material. */
131
131
  :host:not([inline]) .surface {
132
- --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
132
+ --_ui-material-glassiness: calc(clamp(0, var(--ui-glassiness, 0), 1) + 2 * pow(clamp(0, var(--ui-glassiness, 0), 1), 4));
133
133
  --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
134
134
  --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
135
135
  --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.28) * 8px);
@@ -100,7 +100,7 @@
100
100
  /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
101
101
  transparency, saturation and edge light belong to the surrounding decorative material. */
102
102
  .surface {
103
- --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
103
+ --_ui-material-glassiness: calc(clamp(0, var(--ui-glassiness, 0), 1) + 2 * pow(clamp(0, var(--ui-glassiness, 0), 1), 4));
104
104
  --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
105
105
  --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
106
106
  --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.55) * 8px);
@@ -134,12 +134,6 @@
134
134
  padding-block: max(0px, calc((var(--_row) - max(var(--_line), var(--_ui-radio-size, 1.125rem))) / 2)) !important;
135
135
  }
136
136
 
137
- @media (pointer: coarse) {
138
- :host([size="sm"]) {
139
- --_row: var(--ui-control-min-block-size);
140
- }
141
- }
142
-
143
137
  /* A component that sets its display still honours the hidden attribute on its root. */
144
138
  :host[hidden] {
145
139
  display: none !important;
@@ -150,16 +150,10 @@
150
150
  font-size: var(--ui-font-size-md);
151
151
  }
152
152
 
153
- /* Under touch a small field is still a touch-sized target, as a small button is, and keeps
154
- body-size text: below 16px, iOS zooms the page into the focused field. */
153
+ /* Touch may use body-size text in a small native field to avoid focus zoom; this does not impose a larger visible control height. */
155
154
  @media (pointer: coarse) {
156
- :host {
157
- min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
158
- }
159
-
160
155
  :host([size="sm"]) {
161
- min-block-size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
162
- font-size: inherit;
156
+ font-size: var(--ui-font-size-md);
163
157
  }
164
158
  }
165
159
 
@@ -196,12 +196,6 @@
196
196
  padding-block: max(0px, calc((var(--_row) - max(var(--_line), var(--_ui-switch-track-height, 1.5rem))) / 2)) !important;
197
197
  }
198
198
 
199
- @media (pointer: coarse) {
200
- :host([size="sm"]) {
201
- --_row: var(--ui-control-min-block-size);
202
- }
203
- }
204
-
205
199
  /* A component that sets its display still honours the hidden attribute on its root. */
206
200
  :host[hidden] {
207
201
  display: none !important;
@@ -137,7 +137,7 @@
137
137
  /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
138
138
  transparency, saturation and edge light belong to the surrounding decorative material. */
139
139
  .surface {
140
- --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
140
+ --_ui-material-glassiness: calc(clamp(0, var(--ui-glassiness, 0), 1) + 2 * pow(clamp(0, var(--ui-glassiness, 0), 1), 4));
141
141
  --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
142
142
  --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
143
143
  --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.08) * 8px);