@threadlabs/looma 0.34.0 → 0.35.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 (102) hide show
  1. package/components/ui-badge/ui-badge.html +11 -3
  2. package/components/ui-button/ui-button.html +29 -4
  3. package/components/ui-card/ui-card.html +15 -13
  4. package/components/ui-checkbox/ui-checkbox.html +4 -2
  5. package/components/ui-dialog/ui-dialog.html +2 -0
  6. package/components/ui-icon-button/ui-icon-button.html +22 -8
  7. package/components/ui-input/ui-input.html +2 -1
  8. package/components/ui-input-group/ui-input-group.html +4 -1
  9. package/components/ui-light-editor/ui-light-editor.html +45 -0
  10. package/components/ui-light-editor/ui-light-editor.js +53 -0
  11. package/components/ui-menu/ui-menu.html +2 -0
  12. package/components/ui-number-input/ui-number-input.html +2 -1
  13. package/components/ui-number-input/ui-number-input.js +6 -3
  14. package/components/ui-popover/ui-popover.html +2 -0
  15. package/components/ui-reel/ui-reel.html +2 -1
  16. package/components/ui-select/ui-select.html +9 -7
  17. package/components/ui-switch/ui-switch.html +3 -0
  18. package/components/ui-tabs/ui-tabs.html +2 -3
  19. package/components/ui-tabs/ui-tabs.js +0 -9
  20. package/components/ui-textarea/ui-textarea.html +2 -1
  21. package/components/ui-tooltip/ui-tooltip.html +2 -1
  22. package/dist/index.js +24 -23
  23. package/docs/README.md +29 -3
  24. package/docs/card.html +7 -6
  25. package/docs/catalog-view.mjs +2 -1
  26. package/docs/catalog.json +575 -53
  27. package/docs/customizer-render.mjs +31 -16
  28. package/docs/customizer.js +72 -19
  29. package/docs/index.d.ts +4 -1
  30. package/docs/index.mjs +1 -1
  31. package/docs/render.mjs +1 -1
  32. package/docs/site.mjs +33 -22
  33. package/docs/theme-session.mjs +4 -2
  34. package/docs/theme.mjs +61 -7
  35. package/package.json +2 -2
  36. package/styles/ui-badge.css +11 -6
  37. package/styles/ui-button.css +29 -4
  38. package/styles/ui-card.css +9 -9
  39. package/styles/ui-checkbox.css +4 -2
  40. package/styles/ui-dialog.css +4 -0
  41. package/styles/ui-icon-button.css +22 -8
  42. package/styles/ui-input-group.css +4 -1
  43. package/styles/ui-input.css +2 -1
  44. package/styles/ui-light-editor.css +28 -0
  45. package/styles/ui-menu.css +2 -0
  46. package/styles/ui-popover.css +2 -0
  47. package/styles/ui-select.css +9 -7
  48. package/styles/ui-switch.css +3 -0
  49. package/styles/ui-tabs.css +2 -3
  50. package/styles/ui-textarea.css +2 -1
  51. package/styles/ui-tooltip.css +2 -1
  52. package/theme-light.css +1 -0
  53. package/theme-system.css +43 -7
  54. package/tokens.css +5 -1
  55. package/vanilla/UiCard.d.ts +2 -1
  56. package/vanilla/UiCard.js +12 -12
  57. package/vanilla/UiLightEditor.d.ts +29 -0
  58. package/vanilla/UiLightEditor.js +102 -0
  59. package/vanilla/UiNumberInput.js +27 -20
  60. package/vanilla/index.js +1 -0
  61. package/vue/UiBadge.vue +29 -4
  62. package/vue/UiButton.vue +33 -4
  63. package/vue/UiCard.d.ts +8 -2
  64. package/vue/UiCard.vue +41 -17
  65. package/vue/UiCheckbox.vue +4 -2
  66. package/vue/UiDialog.vue +4 -0
  67. package/vue/UiIconButton.vue +26 -11
  68. package/vue/UiInput.vue +2 -1
  69. package/vue/UiInputGroup.vue +4 -1
  70. package/vue/UiLightEditor.d.ts +75 -0
  71. package/vue/UiLightEditor.js +2 -0
  72. package/vue/UiLightEditor.vue +402 -0
  73. package/vue/UiMenu.vue +2 -0
  74. package/vue/UiNumberInput.vue +32 -3
  75. package/vue/UiPopover.vue +2 -0
  76. package/vue/UiReel.vue +1 -1
  77. package/vue/UiSelect.vue +16 -10
  78. package/vue/UiSwitch.vue +3 -0
  79. package/vue/UiTabs.vue +2 -3
  80. package/vue/UiTextarea.vue +2 -1
  81. package/vue/UiTooltip.vue +2 -1
  82. package/vue/chunks/UiBadge.js +1 -1
  83. package/vue/chunks/UiButton.js +1 -1
  84. package/vue/chunks/UiCard.js +33 -5
  85. package/vue/chunks/UiCheckbox.js +1 -1
  86. package/vue/chunks/UiDialog.js +1 -1
  87. package/vue/chunks/UiIconButton.js +1 -1
  88. package/vue/chunks/UiInput.js +1 -1
  89. package/vue/chunks/UiInputGroup.js +1 -1
  90. package/vue/chunks/UiLightEditor.js +347 -0
  91. package/vue/chunks/UiMenu.js +1 -1
  92. package/vue/chunks/UiNumberInput.js +21 -8
  93. package/vue/chunks/UiPopover.js +1 -1
  94. package/vue/chunks/UiReel.js +2 -2
  95. package/vue/chunks/UiSelect.js +1 -1
  96. package/vue/chunks/UiSwitch.js +1 -1
  97. package/vue/chunks/UiTabs.js +1 -1
  98. package/vue/chunks/UiTextarea.js +1 -1
  99. package/vue/chunks/UiTooltip.js +1 -1
  100. package/vue/components.css +312 -71
  101. package/vue/index.d.ts +1 -0
  102. package/vue/index.js +2 -1
@@ -61,7 +61,7 @@
61
61
  border-radius: var(--ui-select-radius, var(--ui-field-radius, var(--ui-radius-md)));
62
62
  background-color: var(--ui-select-surface, var(--ui-control-surface, var(--ui-surface-elevated)));
63
63
  color: var(--ui-text-primary);
64
- color-scheme: light dark;
64
+ color-scheme: inherit;
65
65
  font: inherit;
66
66
  line-height: var(--ui-line-height-tight);
67
67
  box-shadow: var(--ui-select-shadow, var(--ui-shadow-sm));
@@ -74,15 +74,16 @@
74
74
  /* The select draws its own chevron: the native caret cannot be inset or sized consistently.
75
75
  * The root stays a native <s-lect>, so the icon is a background image rather than an element. */
76
76
  :scope:where([data-component~="ui-select"]) {
77
+ --_ui-select-highlight: var(--ui-surface-highlight, linear-gradient(transparent, transparent));
77
78
  appearance: none;
78
79
  padding-inline-end: calc(var(--ui-space-3) + 1.5rem) !important;
79
80
  background-image: var(
80
81
  --ui-select-chevron,
81
82
  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c5c58' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
82
- );
83
+ ), var(--_ui-select-highlight);
83
84
  background-repeat: no-repeat;
84
- background-position: right var(--ui-space-3) center;
85
- background-size: 1.125rem 1.125rem;
85
+ background-position: right var(--ui-space-3) center, center;
86
+ background-size: 1.125rem 1.125rem, 100% 100%;
86
87
  }
87
88
 
88
89
  :scope:where([data-component~="ui-select"]):hover:not(:focus):not(:disabled):not([aria-invalid="true"]):not(:is(:user-invalid, [data-user-invalid])) {
@@ -114,6 +115,7 @@
114
115
  }
115
116
 
116
117
  :scope:where([data-component~="ui-select"]):disabled {
118
+ --_ui-select-highlight: none;
117
119
  background-color: var(--ui-control-surface-disabled, var(--ui-surface-muted));
118
120
  color: var(--ui-disabled-text);
119
121
  box-shadow: none;
@@ -124,8 +126,8 @@
124
126
  min-block-size: var(--ui-control-size-sm);
125
127
  padding: var(--ui-control-inset-block-sm, var(--ui-space-1)) var(--ui-space-2) !important;
126
128
  padding-inline-end: calc(var(--ui-space-2) + var(--ui-icon-size-sm) + var(--ui-space-1)) !important;
127
- background-position: right var(--ui-space-2) center;
128
- background-size: var(--ui-icon-size-sm) var(--ui-icon-size-sm);
129
+ background-position: right var(--ui-space-2) center, center;
130
+ background-size: var(--ui-icon-size-sm) var(--ui-icon-size-sm), 100% 100%;
129
131
  font-size: var(--ui-font-size-sm);
130
132
  }
131
133
 
@@ -133,7 +135,7 @@
133
135
  min-block-size: var(--ui-control-size-lg);
134
136
  padding: var(--ui-control-inset-block-lg, var(--ui-space-3)) var(--ui-space-4) !important;
135
137
  padding-inline-end: calc(var(--ui-space-4) + 1.5rem) !important;
136
- background-position: right var(--ui-space-4) center;
138
+ background-position: right var(--ui-space-4) center, center;
137
139
  font-size: var(--ui-font-size-md);
138
140
  }
139
141
 
@@ -84,6 +84,7 @@
84
84
  border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
85
85
  border-radius: var(--ui-radius-round);
86
86
  background-color: var(--ui-control-surface, var(--ui-surface-default));
87
+ background-image: var(--ui-surface-highlight, none);
87
88
  box-shadow: var(--ui-control-inset);
88
89
  cursor: pointer;
89
90
  transition: background-color var(--ui-motion-base) var(--ui-motion-ease), border-color var(--ui-motion-base) var(--ui-motion-ease);
@@ -105,6 +106,7 @@
105
106
 
106
107
  input:checked {
107
108
  background-color: var(--ui-accent-solid);
109
+ background-image: var(--ui-accent-highlight, none);
108
110
  border-color: var(--ui-accent-solid);
109
111
  }
110
112
 
@@ -128,6 +130,7 @@
128
130
  :scope:where([data-component~="ui-switch"])[data-ui-switch-state~="disabled"] input {
129
131
  border-color: var(--ui-disabled-border);
130
132
  background-color: var(--ui-disabled-surface);
133
+ background-image: none;
131
134
  box-shadow: none;
132
135
  cursor: not-allowed;
133
136
  }
@@ -59,10 +59,9 @@
59
59
  max-inline-size: 100%;
60
60
  /* Tabs that do not fit scroll sideways rather than wrapping or squeezing. */
61
61
  overflow-x: auto;
62
- /* overflow-x: auto would make the block axis scrollable too; a sideways swipe must not scroll the
63
- strip or the page vertically. */
62
+ /* Contain sideways overscroll without trapping vertical page scrolling. */
64
63
  overflow-y: hidden;
65
- overscroll-behavior: contain;
64
+ overscroll-behavior-inline: contain;
66
65
  scrollbar-width: thin;
67
66
  border-block-end: var(--ui-border-width) solid var(--ui-border-divider);
68
67
  }
@@ -72,7 +72,8 @@
72
72
  border: var(--ui-textarea-border-width, var(--_ui-default-textarea-border-width, var(--ui-border-width))) solid
73
73
  var(--ui-textarea-border, var(--_ui-default-textarea-border, var(--ui-control-border, var(--ui-border-strong))));
74
74
  border-radius: var(--ui-textarea-radius, var(--_ui-default-textarea-radius, var(--ui-field-radius, var(--ui-radius-md))));
75
- background: var(--ui-textarea-surface, var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
75
+ background-color: var(--ui-textarea-surface, var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
76
+ background-image: var(--_ui-default-textarea-highlight, var(--ui-surface-highlight, none));
76
77
  color: var(--ui-text-primary);
77
78
  font: inherit;
78
79
  line-height: var(--ui-line-height-md);
@@ -204,7 +204,8 @@
204
204
  border-inline-end-width: var(--ui-border-width);
205
205
  border-block-end-width: var(--ui-border-width);
206
206
  border-end-end-radius: var(--ui-border-width);
207
- transform: rotate(45deg) scaleX(1.25) scaleY(0.85);
207
+ /* Stretch in screen axes after rotation so both arrow shoulders stay level. */
208
+ transform: scale(1.25, 0.85) rotate(45deg);
208
209
  }
209
210
 
210
211
  :scope:where([data-component~="ui-tooltip"])[data-ui-actual-placement="bottom"] .surface:where(:not([data-component], [data-slotted]))::after {
package/theme-light.css CHANGED
@@ -2,6 +2,7 @@
2
2
  :root:not([data-theme], [data-contrast="high"]),
3
3
  [data-theme="light"] {
4
4
  color-scheme: light;
5
+ --ui-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c5c58' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
5
6
  /* The seeds, and only the seeds. Neutrals, hovers, tints, and disabled colours are mixed from
6
7
  these in tokens.css, so a product themes Looma by changing these eleven values. */
7
8
  --ui-surface: #ffffff;
package/theme-system.css CHANGED
@@ -2,6 +2,9 @@
2
2
  Existing public roles remain the customization interface; no component selectors. */
3
3
  /* Resolve shared geometry once where it is declared, rather than once per consuming
4
4
  control's font. Palette roles remain unregistered so light-dark resolves locally. */
5
+ /* Reserve the same order when the remembered theme arrives before baseline CSS. */
6
+ @layer tokens, base, theme, components;
7
+
5
8
  @property --ui-font-size { syntax: "<length>"; inherits: true; initial-value: 16px; }
6
9
  @property --ui-control-size { syntax: "<length>"; inherits: true; initial-value: 40px; }
7
10
  @property --ui-radius-md { syntax: "<length>"; inherits: true; initial-value: 8px; }
@@ -18,6 +21,12 @@
18
21
  --ui-overlay-translucency: 0;
19
22
  --ui-glassiness: 0;
20
23
  --ui-surface-separation: 0;
24
+ --ui-finish: 0;
25
+ --ui-glow: 0;
26
+ --ui-light-x: 0.5;
27
+ --ui-light-y: 0;
28
+ --ui-light-spread: 0.5;
29
+ --ui-light-strength: 0.65;
21
30
  }
22
31
 
23
32
  :where(:root, [data-theme], [data-contrast]) {
@@ -58,26 +67,47 @@
58
67
  --_ui-theme-outer: max(0, var(--ui-outer-depth));
59
68
  --_ui-theme-inner: max(0, var(--ui-inner-depth));
60
69
  --_ui-theme-edge: clamp(0, var(--ui-edge-light), 1);
61
- --_ui-theme-edge-paint: inset 1px 1px 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * 0.08)), inset -1px -1px 0 rgb(0 0 0 / calc(var(--_ui-theme-edge) * 0.08));
70
+ --_ui-light-inline: calc((0.5 - var(--ui-light-x)) * 2px);
71
+ --_ui-shadow-x: calc((0.5 - var(--ui-light-x)) * 2);
72
+ --_ui-shadow-y: calc((0.5 - var(--ui-light-y)) * 2);
73
+ --_ui-light-block: calc((0.5 - var(--ui-light-y)) * 2px);
74
+ --_ui-theme-edge-paint: inset var(--_ui-light-inline) var(--_ui-light-block) 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * var(--ui-light-strength) * 0.3)), inset calc(-1 * var(--_ui-light-inline)) calc(-1 * var(--_ui-light-block)) 0 rgb(0 0 0 / calc(var(--_ui-theme-edge) * 0.1));
62
75
  --ui-action-edge: var(--_ui-theme-edge-paint);
63
- --ui-shadow-xs: 0 calc(1px * var(--_ui-theme-outer)) calc(2px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.08);
64
- --ui-shadow-sm: 0 calc(1px * var(--_ui-theme-outer)) calc(3px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), 0 calc(4px * var(--_ui-theme-outer)) calc(12px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
76
+ --ui-shadow-xs: calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(2px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.08);
77
+ --ui-shadow-sm: calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(3px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(12px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
65
78
  --ui-shadow-md: var(--ui-shadow-sm);
66
- --ui-shadow-lg: 0 calc(8px * var(--_ui-theme-outer)) calc(24px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), 0 calc(4px * var(--_ui-theme-outer)) calc(8px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
79
+ --ui-shadow-lg: calc(8px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(8px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(24px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(8px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
67
80
  --ui-shadow-xl: var(--ui-shadow-lg);
68
- --ui-action-shadow: var(--ui-shadow-sm);
81
+ --ui-action-shadow: var(--ui-action-edge), var(--ui-shadow-sm);
69
82
  --ui-raised: var(--ui-shadow-sm);
70
83
  --ui-elevation-tooltip: var(--ui-shadow-sm);
71
84
  --ui-elevation-overlay: var(--ui-shadow-lg);
72
85
  --ui-elevation-dialog: var(--ui-shadow-lg);
73
- --ui-control-inset: inset 0 calc(1px * var(--_ui-theme-inner)) calc(3px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.15), inset 0 -1px 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * 0.18));
74
- --ui-pressed: inset 0 calc(2px * var(--_ui-theme-inner)) calc(4px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.2);
86
+ --ui-control-inset: inset calc(var(--_ui-light-inline) * var(--_ui-theme-inner)) calc(var(--_ui-light-block) * var(--_ui-theme-inner)) calc(3px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.15), inset calc(-1 * var(--_ui-light-inline)) calc(-1 * var(--_ui-light-block)) 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * var(--ui-light-strength) * 0.18)), var(--ui-material-glow);
87
+ --ui-pressed: inset calc(2 * var(--_ui-light-inline) * var(--_ui-theme-inner)) calc(2 * var(--_ui-light-block) * var(--_ui-theme-inner)) calc(4px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.2);
75
88
  --ui-overlay-surface: color-mix(in srgb, var(--ui-surface-raised) calc((1 - clamp(0, var(--ui-overlay-translucency), 1)) * 100%), transparent);
76
89
  /* Decorative outer material is allowed to transmit the scene. Content keeps
77
90
  its own opaque plane; changing the scene cannot undermine text contrast. */
78
91
  --ui-material-content: var(--ui-surface-raised);
79
92
  --ui-material-glass: color-mix(in srgb, var(--ui-surface-raised) calc((1 - clamp(0, var(--ui-overlay-translucency), 1)) * 35%), transparent);
80
93
  --ui-material-edge: color-mix(in srgb, var(--ui-surface-raised) 80%, var(--ui-text));
94
+ /* Each role has a bounded reflection colour. Shared source coordinates are
95
+ relative to each surface, so size and position never change the lighting. */
96
+ --ui-surface-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-surface-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
97
+ --ui-neutral-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-neutral-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
98
+ --ui-accent-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-accent-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
99
+ --ui-danger-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-danger-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
100
+ --ui-success-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-success-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
101
+ --ui-warning-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-warning-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
102
+ --ui-info-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-info-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
103
+ --ui-material-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-accent) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
104
+ --ui-neutral-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-text) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
105
+ --ui-accent-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-accent) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
106
+ --ui-danger-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-danger) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
107
+ --ui-success-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-success) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
108
+ --ui-warning-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-warning) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
109
+ --ui-info-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-info) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
110
+ --ui-raised-highlight: var(--ui-surface-highlight);
81
111
 
82
112
  /* Existing timing and easing names stay canonical. */
83
113
  --ui-motion-press: var(--ui-motion-fast);
@@ -93,4 +123,10 @@
93
123
  --ui-press-scale: 1;
94
124
  }
95
125
  }
126
+ @media (prefers-reduced-transparency: reduce), (forced-colors: active) {
127
+ :where(:root, [data-theme], [data-contrast]) {
128
+ --ui-finish: 0;
129
+ --ui-glow: 0;
130
+ }
131
+ }
96
132
  }
package/tokens.css CHANGED
@@ -85,6 +85,10 @@
85
85
  never has to: these exist so components share one vocabulary, not to be configured. */
86
86
  :root,
87
87
  :where([data-theme], [data-contrast]) {
88
+ /* Neutral is a quiet filled surface, never the text colour inverted. */
89
+ --ui-neutral-surface: color-mix(in srgb, var(--ui-text) 6%, var(--ui-surface-raised));
90
+ --ui-neutral-hover: color-mix(in srgb, var(--ui-text) 10%, var(--ui-surface-raised));
91
+ --ui-neutral-active: color-mix(in srgb, var(--ui-text) 14%, var(--ui-surface-raised));
88
92
  --ui-accent-line-width: var(--ui-border-width);
89
93
 
90
94
  /* Type scale, from the base size. */
@@ -247,7 +251,7 @@
247
251
  --ui-control-surface: var(--ui-surface);
248
252
  --ui-control-surface-disabled: var(--ui-surface-muted);
249
253
  --ui-control-border-hover: color-mix(in oklab, var(--ui-text) 50%, var(--ui-surface));
250
- --ui-control-placeholder: var(--ui-text-secondary);
254
+ --ui-control-placeholder: color-mix(in oklab, var(--ui-text) 58%, var(--ui-control-surface));
251
255
  --ui-control-focus: var(--ui-focus-ring);
252
256
  /* Derived from the ring, not a near-white tint, so the halo shows on any surface. */
253
257
  --ui-control-focus-halo: color-mix(in srgb, var(--ui-focus-ring) 24%, transparent);
@@ -14,7 +14,8 @@ export interface UiCardProps {
14
14
  padding?: "xs" | "sm" | "md" | "lg" | null;
15
15
  size?: "content" | "sm" | "md" | "lg" | null;
16
16
  tone?: "neutral" | "accent" | "info" | "success" | "warning" | "danger" | null;
17
- variant?: "outlined" | "subtle" | "elevated" | "glass" | null;
17
+ treatment?: "standard" | "expressive" | null;
18
+ variant?: "outlined" | "subtle" | "elevated" | null;
18
19
  attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
19
20
  children?: readonly (string | Node)[];
20
21
  slots?: Readonly<Record<string, readonly (string | Node)[]>>;
package/vanilla/UiCard.js CHANGED
@@ -12,13 +12,13 @@ const T6 = ["",[],4];
12
12
  const T7 = ["",[]];
13
13
  let P0, P1, P2, P3, P4, P5, P6, P7;
14
14
  const S = { n: [], t: [], f: import.meta.url, g: "ui-card", b: generatedInputs };
15
- const A = [["section",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-variant"]],["article",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-variant"]],["aside",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-variant"]],["div",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-variant"]]];
15
+ const A = [["section",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-treatment","data-ui-card-prop-variant"]],["article",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-treatment","data-ui-card-prop-variant"]],["aside",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-treatment","data-ui-card-prop-variant"]],["div",{},[],"",[],["data-ui-card-state","data-ui-card-prop-as","data-ui-card-prop-padding","data-ui-card-prop-size","data-ui-card-prop-tone","data-ui-card-prop-treatment","data-ui-card-prop-variant"]]];
16
16
  const Q = [[],[],[],[]];
17
- const D = { g: "ui-card", props: { "as": { "required":false,"values":["div","section","article","aside"],"default":"div", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "padding": { "required":false,"values":["xs","sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "size": { "required":false,"values":["content","sm","md","lg"],"default":"content", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "tone": { "required":false,"values":["neutral","accent","info","success","warning","danger"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "variant": { "required":false,"values":["outlined","subtle","elevated","glass"],"default":"outlined", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] } } };
17
+ const D = { g: "ui-card", props: { "as": { "required":false,"values":["div","section","article","aside"],"default":"div", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "padding": { "required":false,"values":["xs","sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "size": { "required":false,"values":["content","sm","md","lg"],"default":"content", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "tone": { "required":false,"values":["neutral","accent","info","success","warning","danger"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "treatment": { "required":false,"values":["standard","expressive"],"default":"standard", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "variant": { "required":false,"values":["outlined","subtle","elevated"],"default":"outlined", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] } } };
18
18
 
19
19
  export function createUiCard(options = {}, html) {
20
20
  const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
21
- const v = [null, null, null, null, null];
21
+ const v = [null, null, null, null, null, null];
22
22
  let B = acceptProps(undefined, D, S.n, v, componentProps, [], html);
23
23
  let a = ((v[0] === "section") ? 0 : (v[0] === "article") ? 1 : (v[0] === "aside") ? 2 : 3);
24
24
  let element;
@@ -92,8 +92,8 @@ export function createUiCard(options = {}, html) {
92
92
  return r;
93
93
  };
94
94
  const p0 = (r, c, d) => {
95
- if (c & 30) {
96
- const x0 = hostState(["padding","variant","tone","size"], [v[1], v[4], v[3], v[2]]);
95
+ if (c & 62) {
96
+ const x0 = hostState(["padding","variant","treatment","tone","size"], [v[1], v[5], v[4], v[3], v[2]]);
97
97
  const s0 = x0;
98
98
  if (s0 !== r.v0) writeAttribute(r.n, "data-ui-card-state", (r.v0 = s0) === "" ? null : s0);
99
99
  }
@@ -109,8 +109,8 @@ export function createUiCard(options = {}, html) {
109
109
  return r;
110
110
  };
111
111
  const p2 = (r, c, d) => {
112
- if (c & 30) {
113
- const x0 = hostState(["padding","variant","tone","size"], [v[1], v[4], v[3], v[2]]);
112
+ if (c & 62) {
113
+ const x0 = hostState(["padding","variant","treatment","tone","size"], [v[1], v[5], v[4], v[3], v[2]]);
114
114
  const s0 = x0;
115
115
  if (s0 !== r.v0) writeAttribute(r.n, "data-ui-card-state", (r.v0 = s0) === "" ? null : s0);
116
116
  }
@@ -126,8 +126,8 @@ export function createUiCard(options = {}, html) {
126
126
  return r;
127
127
  };
128
128
  const p4 = (r, c, d) => {
129
- if (c & 30) {
130
- const x0 = hostState(["padding","variant","tone","size"], [v[1], v[4], v[3], v[2]]);
129
+ if (c & 62) {
130
+ const x0 = hostState(["padding","variant","treatment","tone","size"], [v[1], v[5], v[4], v[3], v[2]]);
131
131
  const s0 = x0;
132
132
  if (s0 !== r.v0) writeAttribute(r.n, "data-ui-card-state", (r.v0 = s0) === "" ? null : s0);
133
133
  }
@@ -143,8 +143,8 @@ export function createUiCard(options = {}, html) {
143
143
  return r;
144
144
  };
145
145
  const p6 = (r, c, d) => {
146
- if (c & 30) {
147
- const x0 = hostState(["padding","variant","tone","size"], [v[1], v[4], v[3], v[2]]);
146
+ if (c & 62) {
147
+ const x0 = hostState(["padding","variant","treatment","tone","size"], [v[1], v[5], v[4], v[3], v[2]]);
148
148
  const s0 = x0;
149
149
  if (s0 !== r.v0) writeAttribute(r.n, "data-ui-card-state", (r.v0 = s0) === "" ? null : s0);
150
150
  }
@@ -179,4 +179,4 @@ export function createUiCard(options = {}, html) {
179
179
  manageProps(I);
180
180
  return element;
181
181
  }
182
- defineComponent("ui-card", createUiCard, ["as","padding","size","tone","variant"]);
182
+ defineComponent("ui-card", createUiCard, ["as","padding","size","tone","treatment","variant"]);
@@ -0,0 +1,29 @@
1
+ // Generated by HTML Next 1.0.0-alpha.69 for Vanilla DOM. Do not edit.
2
+ export interface UiLightEditorEventMap {
3
+ input: CustomEvent<{ readonly x: number; readonly y: number }>;
4
+ change: CustomEvent<{ readonly x: number; readonly y: number }>;
5
+ }
6
+ export interface UiLightEditorElement extends HTMLSpanElement {
7
+ addEventListener<K extends keyof UiLightEditorEventMap>(type: K, listener: (this: UiLightEditorElement, event: UiLightEditorEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
8
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: UiLightEditorElement, event: HTMLElementEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
9
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
10
+ removeEventListener<K extends keyof UiLightEditorEventMap>(type: K, listener: (this: UiLightEditorElement, event: UiLightEditorEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
11
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: UiLightEditorElement, event: HTMLElementEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
12
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
13
+ }
14
+ export interface UiLightEditorProps {
15
+ disabled?: boolean | null;
16
+ label?: string | null;
17
+ size?: "sm" | "md" | "lg" | null;
18
+ x?: number | null;
19
+ y?: number | null;
20
+ attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
21
+ children?: readonly (string | Node)[];
22
+ slots?: Readonly<Record<string, readonly (string | Node)[]>>;
23
+ }
24
+ export declare function createUiLightEditor(props?: UiLightEditorProps): UiLightEditorElement;
25
+ declare global {
26
+ interface ComponentTagMap {
27
+ "ui-light-editor": { element: UiLightEditorElement; props: Omit<UiLightEditorProps, "attributes" | "children" | "slots"> };
28
+ }
29
+ }
@@ -0,0 +1,102 @@
1
+ // Generated by HTML Next 1.0.0-alpha.69 for Vanilla DOM. Do not edit.
2
+ import { attachGeneratedController, buildTemplate, NONCONFORMING, textCall, toAttribute, writeAttribute, dispatchDeclared, detailCheck, dispose, formatOf, keywordFormat, acceptProps, manageProps, generatedInputs, project, fillSlot, checkBoolean, checkFormat, checkNumber, checkObject, checkString, defineComponent, activateModule } from "@nextwebwg/html-next/generated-runtime";
3
+ import * as controller from "../components/ui-light-editor/ui-light-editor.js";
4
+ import "../styles/ui-light-editor.css";
5
+
6
+ const T0 = ["",[],"\n ",["span",["class","stage","role","group"],"\n ",["span",["class","plane"],"\n ",["svg",["viewBox","0 0 100 60","preserveAspectRatio","none","aria-hidden","true"],["path",["d","M0 30 H100 M50 0 V60"]]],"\n ",["span",["class","specimen"],4],"\n ",["button",["type","button","class","source"]],"\n "],"\n "],"\n ",["span",["class","coordinates"],"\n ",["ui-number-input",["data-coordinate","x","min","0","max","100","step","1","unit","%","label","Light horizontal position"]],"\n ",["ui-number-input",["data-coordinate","y","min","0","max","100","step","1","unit","%","label","Light vertical position"]],"\n "],"\n ",["span",["class","hint"],"Drag the light, use arrow keys, or enter its position. Top centre is 50%, 0%."],"\n "];
7
+ const T1 = ["",[]];
8
+ let P0, P1;
9
+ const S = { n: ["horizontal","vertical"], t: ["s","s"], f: import.meta.url, g: "ui-light-editor", d: { "input": [detailCheck(checkObject([["x", checkNumber, false], ["y", checkNumber, false]], false)), true, true, false], "change": [detailCheck(checkObject([["x", checkNumber, false], ["y", checkNumber, false]], false)), true, true, false] }, x: dispatchDeclared, a: (host, I) => C(host, I), b: generatedInputs, i: ["50", "0"] };
10
+ const D = { g: "ui-light-editor", props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false,"default":"Light position", c: checkString, t: "string", j: 0, m: "s" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "x": { "required":false,"default":0.5, c: checkNumber, t: "number", j: 0, m: "n" }, "y": { "required":false,"default":0, c: checkNumber, t: "number", j: 0, m: "n" } } };
11
+ const C = (host) => activateModule(controller, host);
12
+
13
+ export function createUiLightEditor(options = {}, html) {
14
+ const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
15
+ const element = document.createElement("span");
16
+ for (const [name, value] of Object.entries(attributes)) {
17
+ if (value === null || value === undefined || value === false) continue;
18
+ element.setAttribute(name, value === true ? "" : String(value));
19
+ }
20
+ element.setAttribute("data-component", "ui-light-editor");
21
+ element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
22
+ const v = ["50", "0", null, null, null, null, null];
23
+ const B = acceptProps(element, D, S.n, v, componentProps, [], html);
24
+ const m1 = (d) => {
25
+ const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
26
+ const r = { n };
27
+ p1(r, -1, d);
28
+ return r;
29
+ };
30
+ const p1 = (r, c, d) => {
31
+ };
32
+ const p0 = (r, c, d) => {
33
+ if (c & 8) {
34
+ const x0 = v[3];
35
+ const s0 = toAttribute(x0, "aria-label");
36
+ if (s0 !== r.v0) writeAttribute(r.a0, "aria-label", r.v0 = s0);
37
+ }
38
+ if (c & 4) {
39
+ const x1 = v[2];
40
+ const s1 = toAttribute(x1, "disabled");
41
+ if (s1 !== r.v1) writeAttribute(r.a3, "disabled", r.v1 = s1);
42
+ }
43
+ if (c & 8) {
44
+ const x2 = textCall("concat", [v[3], ". Arrow keys move the source; Shift moves faster."]);
45
+ if (x2 !== NONCONFORMING) {
46
+ const s2 = toAttribute(x2, "aria-label");
47
+ if (s2 !== r.v2) writeAttribute(r.a3, "aria-label", r.v2 = s2);
48
+ }
49
+ }
50
+ if (c & 1) {
51
+ const x3 = v[0];
52
+ const s3 = toAttribute(x3, "value");
53
+ if (s3 !== r.v3) writeAttribute(r.a4, "value", r.v3 = s3);
54
+ }
55
+ if (c & 1073741840) {
56
+ const x4 = v[4];
57
+ const s4 = toAttribute(x4, "size");
58
+ if (s4 !== r.v4) writeAttribute(r.a4, "size", r.v4 = s4);
59
+ }
60
+ if (c & 4) {
61
+ const x5 = v[2];
62
+ const s5 = toAttribute(x5, "disabled");
63
+ if (s5 !== r.v5) writeAttribute(r.a4, "disabled", r.v5 = s5);
64
+ }
65
+ if (c & 2) {
66
+ const x6 = v[1];
67
+ const s6 = toAttribute(x6, "value");
68
+ if (s6 !== r.v6) writeAttribute(r.a5, "value", r.v6 = s6);
69
+ }
70
+ if (c & 1073741840) {
71
+ const x7 = v[4];
72
+ const s7 = toAttribute(x7, "size");
73
+ if (s7 !== r.v7) writeAttribute(r.a5, "size", r.v7 = s7);
74
+ }
75
+ if (c & 4) {
76
+ const x8 = v[2];
77
+ const s8 = toAttribute(x8, "disabled");
78
+ if (s8 !== r.v8) writeAttribute(r.a5, "disabled", r.v8 = s8);
79
+ }
80
+ if (r.f0 === undefined) { r.f0 = 1; const at = fillSlot(r.a2, r.e0, "", J, false, undefined, d);
81
+ if (Array.isArray(at)) (r.z ??= []).push(() => { at[0].l.delete(at[1]); dispose(at[1]); }); else if (at !== undefined) { r.b0 = m1(d); at.before(r.b0.n); } }
82
+ else if (r.b0 !== undefined) p1(r.b0, c, d);
83
+ };
84
+ const t0 = element.firstChild.nextSibling;
85
+ const t1 = t0.firstChild.nextSibling;
86
+ const t2 = t1.firstChild.nextSibling.nextSibling.nextSibling;
87
+ const t3 = t2.firstChild;
88
+ const t4 = t2.nextSibling.nextSibling;
89
+ const t5 = t0.nextSibling.nextSibling;
90
+ const t6 = t5.firstChild.nextSibling;
91
+ const t7 = t6.nextSibling.nextSibling;
92
+ const R = { a0: t0, a3: t4, a4: t6, a5: t7, v0: null, v1: null, v2: null, v3: null, v4: null, v5: null, v6: null, v7: null, v8: null, a2: t3, e0: t3.nextSibling, b0: undefined, f0: undefined };
93
+ const I = { B };
94
+ const J = project(I, children, slots);
95
+ I.R = new Set();
96
+ attachGeneratedController(element, S, v, (c, d) => { ((c, d) => p0(R, c, d))(c, d); for (const f of I.R) f(c, d); }, undefined, undefined, I);
97
+ manageProps(I);
98
+ I.r["plane"] = t1;
99
+ I.r["source"] = t4;
100
+ return element;
101
+ }
102
+ defineComponent("ui-light-editor", createUiLightEditor, ["disabled","label","size","x","y"]);
@@ -1,11 +1,11 @@
1
1
  // Generated by HTML Next 1.0.0-alpha.69 for Vanilla DOM. Do not edit.
2
- import { attachGeneratedController, buildTemplate, NONCONFORMING, textCall, toAttribute, writeAttribute, dispatchDeclared, detailCheck, formatOf, keywordFormat, acceptProps, manageProps, generatedInputs, checkBoolean, checkFormat, checkNumber, checkObject, checkString, defineComponent, activateModule } from "@nextwebwg/html-next/generated-runtime";
2
+ import { attachGeneratedController, stateInitializers, buildTemplate, checkReference, NONCONFORMING, textCall, toAttribute, writeAttribute, dispatchDeclared, detailCheck, formatOf, keywordFormat, acceptProps, manageProps, generatedInputs, awaitInput, inputRead, READY_INPUT, UNRESOLVED_INPUT, checkBoolean, checkFormat, checkNumber, checkObject, checkString, defineComponent, activateModule } from "@nextwebwg/html-next/generated-runtime";
3
3
  import * as controller from "../components/ui-number-input/ui-number-input.js";
4
4
  import "../styles/ui-number-input.css";
5
5
 
6
6
  const T0 = ["",[],"\n ",["ui-icon-button",["data-number-step","decrease","match-button","","type","button"],["ui-icon",["name","minus"]]],"\n ",["ui-input",["data-ui-field-control","","inputmode","decimal","spellcheck","false","aria-description","Enter calculates arithmetic. Arrow keys step; Shift changes ten steps."]],"\n ",["ui-icon-button",["data-number-step","increase","match-button","","type","button"],["ui-icon",["name","plus"]]],"\n "];
7
7
  let P0;
8
- const S = { n: [], t: [], f: import.meta.url, g: "ui-number-input", d: { "input": [detailCheck(checkObject([["value", checkString, false]], false)), true, true, false], "change": [detailCheck(checkObject([["value", checkString, false]], false)), true, true, false] }, x: dispatchDeclared, a: (host, I) => C(host, I), b: generatedInputs };
8
+ const S = { n: ["display"], t: ["s"], f: import.meta.url, g: "ui-number-input", d: { "input": [detailCheck(checkObject([["value", checkString, false]], false)), true, true, false], "change": [detailCheck(checkObject([["value", checkString, false]], false)), true, true, false] }, x: dispatchDeclared, a: (host, I) => C(host, I), b: generatedInputs };
9
9
  const D = { g: "ui-number-input", props: { "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false,"default":"Value", c: checkString, t: "string", j: 0, m: "s" }, "max": { "required":false,"default":1000000, c: checkNumber, t: "number", j: 0, m: "n" }, "min": { "required":false,"default":-1000000, c: checkNumber, t: "number", j: 0, m: "n" }, "name": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "step": { "required":false,"default":1, c: checkNumber, t: "number", j: 0, m: "n" }, "unit": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" }, "value": { "required":false,"default":"0", c: checkString, t: "string", j: 0, m: "s" } } };
10
10
  const C = (host) => activateModule(controller, host);
11
11
 
@@ -18,11 +18,15 @@ export function createUiNumberInput(options = {}, html) {
18
18
  }
19
19
  element.setAttribute("data-component", "ui-number-input");
20
20
  element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
21
- const v = [null, null, null, null, null, null, null, null, null];
21
+ const v = [null, null, null, null, null, null, null, null, null, null];
22
22
  const B = acceptProps(element, D, S.n, v, componentProps, [], html);
23
+ const CS = [];
24
+ const inputStatus = (j) => { if (j === 0) return E.status(j); if (j === 1) return awaitInput(B, "disabled", true); if (j === 2) return awaitInput(B, "label", true); if (j === 3) return awaitInput(B, "max", true); if (j === 4) return awaitInput(B, "min", true); if (j === 5) return awaitInput(B, "name", true); if (j === 6) return awaitInput(B, "size", true); if (j === 7) return awaitInput(B, "step", true); if (j === 8) return awaitInput(B, "unit", true); if (j === 9) return awaitInput(B, "value", true); return v[j] === undefined ? UNRESOLVED_INPUT : READY_INPUT; };
25
+ const X = { e: 0, g: (j) => v[j], w: new Set(), a: CS, i: inputStatus };
26
+ const E = stateInitializers(S, v, X, { 0: () => inputRead(v[9], inputStatus(9)) });
23
27
  const p0 = (r, c, d) => {
24
- if (c & 1073741856) {
25
- const x0 = v[5];
28
+ if (c & 1073741888) {
29
+ const x0 = v[6];
26
30
  const s0 = toAttribute(x0, "size");
27
31
  if (s0 !== r.v0) writeAttribute(r.a0, "size", r.v0 = s0);
28
32
  const s3 = toAttribute(x0, "size");
@@ -30,8 +34,8 @@ export function createUiNumberInput(options = {}, html) {
30
34
  const s8 = toAttribute(x0, "size");
31
35
  if (s8 !== r.v8) writeAttribute(r.a2, "size", r.v8 = s8);
32
36
  }
33
- if (c & 1) {
34
- const x1 = v[0];
37
+ if (c & 2) {
38
+ const x1 = v[1];
35
39
  const s1 = toAttribute(x1, "disabled");
36
40
  if (s1 !== r.v1) writeAttribute(r.a0, "disabled", r.v1 = s1);
37
41
  const s4 = toAttribute(x1, "disabled");
@@ -39,30 +43,32 @@ export function createUiNumberInput(options = {}, html) {
39
43
  const s9 = toAttribute(x1, "disabled");
40
44
  if (s9 !== r.v9) writeAttribute(r.a2, "disabled", r.v9 = s9);
41
45
  }
42
- if (c & 2) {
43
- const x2 = textCall("concat", ["Decrease ", v[1]]);
46
+ if (c & 4) {
47
+ const x2 = textCall("concat", ["Decrease ", v[2]]);
44
48
  if (x2 !== NONCONFORMING) {
45
49
  const s2 = toAttribute(x2, "label");
46
50
  if (s2 !== r.v2) writeAttribute(r.a0, "label", r.v2 = s2);
47
51
  }
48
52
  }
49
- if (c & 256) {
50
- const x3 = v[8];
51
- const s5 = toAttribute(x3, "value");
52
- if (s5 !== r.v5) writeAttribute(r.a1, "value", r.v5 = s5);
53
+ if (c & 1) {
54
+ const x3 = (checkReference(S, v[0], "s", "expression:$display:display", "Reference `display` must satisfy string.") ? E.read(0) : NONCONFORMING);
55
+ if (x3 !== NONCONFORMING) {
56
+ const s5 = toAttribute(x3, "value");
57
+ if (s5 !== r.v5) writeAttribute(r.a1, "value", r.v5 = s5);
58
+ }
53
59
  }
54
- if (c & 2) {
55
- const x4 = v[1];
60
+ if (c & 4) {
61
+ const x4 = v[2];
56
62
  const s6 = toAttribute(x4, "aria-label");
57
63
  if (s6 !== r.v6) writeAttribute(r.a1, "aria-label", r.v6 = s6);
58
- const x5 = textCall("concat", ["Increase ", v[1]]);
64
+ const x5 = textCall("concat", ["Increase ", v[2]]);
59
65
  if (x5 !== NONCONFORMING) {
60
66
  const s10 = toAttribute(x5, "label");
61
67
  if (s10 !== r.v10) writeAttribute(r.a2, "label", r.v10 = s10);
62
68
  }
63
69
  }
64
- if (c & 16) {
65
- const x6 = v[4];
70
+ if (c & 32) {
71
+ const x6 = v[5];
66
72
  const s7 = toAttribute(x6, "name");
67
73
  if (s7 !== r.v7) writeAttribute(r.a1, "name", r.v7 = s7);
68
74
  }
@@ -71,8 +77,9 @@ export function createUiNumberInput(options = {}, html) {
71
77
  const t1 = t0.nextSibling.nextSibling;
72
78
  const t2 = t1.nextSibling.nextSibling;
73
79
  const R = { a0: t0, a1: t1, a2: t2, v0: null, v1: null, v2: null, v3: null, v4: null, v5: null, v6: null, v7: null, v8: null, v9: null, v10: null };
74
- const I = { B };
75
- attachGeneratedController(element, S, v, ((c, d) => p0(R, c, d)), undefined, undefined, I);
80
+ const I = { B, U: E };
81
+ I.R = new Set();
82
+ attachGeneratedController(element, S, v, (c, d) => { ((c, d) => p0(R, c, d))(c, d); for (const f of I.R) f(c, d); }, undefined, X, I);
76
83
  manageProps(I);
77
84
  return element;
78
85
  }
package/vanilla/index.js CHANGED
@@ -47,6 +47,7 @@ export * from "./UiIconButton.js";
47
47
  export * from "./UiImage.js";
48
48
  export * from "./UiInput.js";
49
49
  export * from "./UiInputGroup.js";
50
+ export * from "./UiLightEditor.js";
50
51
  export * from "./UiList.js";
51
52
  export * from "./UiListbox.js";
52
53
  export * from "./UiListItem.js";
package/vue/UiBadge.vue CHANGED
@@ -257,9 +257,6 @@ const hostState = computed(() =>
257
257
  /* A count can keep its containing control's contrasting ink instead of reversing it.
258
258
  The faint fill preserves text contrast; a quiet boundary separates the count from its control. */
259
259
 
260
- /* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
261
- surface ink: moving it toward dark-theme primary text would reduce overlay contrast. */
262
-
263
260
  /* An icon mark keeps the existing tone recipe and follows the global spacing and radius. */
264
261
 
265
262
  /* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
@@ -557,8 +554,36 @@ const hostState = computed(() =>
557
554
  border-color: var(--ui-badge-border, color-mix(in srgb, currentColor 20%, transparent));
558
555
  box-shadow: none;
559
556
  }
557
+
560
558
  :global(:scope[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"]:where([data-hn-ui-badge])) {
561
- color: var(--ui-badge-text, var(--_badge-color-text, var(--_badge-surface)));
559
+ --_badge-outline-surface: var(
560
+ --ui-badge-surface,
561
+ var(--_badge-color-surface, color-mix(in srgb, var(--ui-surface-raised) 88%, transparent))
562
+ );
563
+ color: var(--ui-badge-text, var(--_badge-color-text, var(--ui-text-primary)));
564
+ }
565
+ :global(:scope[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"]:not([data-ui-badge-state~="shape=circle"]):where([data-hn-ui-badge])) {
566
+ border-color: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-outline-surface)));
567
+ }
568
+ :global(:scope[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"][data-ui-badge-state~="shape=circle"]:where([data-hn-ui-badge])) {
569
+ --_badge-outline-surface: var(
570
+ --ui-badge-surface,
571
+ var(
572
+ --_badge-color-surface,
573
+ light-dark(
574
+ color-mix(
575
+ in srgb,
576
+ var(--ui-surface-raised) var(--ui-badge-circle-opacity, 66%),
577
+ transparent
578
+ ),
579
+ color-mix(
580
+ in srgb,
581
+ var(--ui-surface-raised) var(--ui-badge-circle-opacity, 56%),
582
+ transparent
583
+ )
584
+ )
585
+ )
586
+ );
562
587
  }
563
588
 
564
589
  :global(:scope[data-ui-badge-state~="variant=outline"]:where([data-hn-ui-badge])) {