@celestia-island/hikari 0.55.302 → 0.55.304

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celestia-island/hikari",
3
- "version": "0.55.302",
3
+ "version": "0.55.304",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Hikari UI library, Vue 3 runtime — one design system for Vue 3 and Rust/WASM applications",
@@ -181,6 +181,13 @@
181
181
  }
182
182
 
183
183
  .hk-affix-tag-x {
184
+ /* Wave B2 hybrid decision: the × keeps its own onmousedown
185
+ prevent-default (tapping must not steal focus or start a selection) and
186
+ its 1.5rem field density, so it deliberately stays a BARE button — the
187
+ contract is pinned Rust-side
188
+ (`affix_tag_close_stays_a_bare_button_by_contract`). What standardizes
189
+ is the INK: it consumes the icon-button channel vars (current values as
190
+ first fallbacks = zero visual change). */
184
191
  flex: none;
185
192
  display: inline-flex;
186
193
  align-items: center;
@@ -191,15 +198,21 @@
191
198
  border: 0;
192
199
  border-radius: var(--radius-full, 999px);
193
200
  background: transparent;
194
- color: rgb(var(--color-muted));
201
+ color: var(--hi-icon-button-icon-color, rgb(var(--color-muted)));
195
202
  cursor: pointer;
196
203
  appearance: none;
197
204
  transition: color 0.12s ease, background 0.12s ease;
198
205
 
199
206
  &:hover,
200
207
  &:focus-visible {
201
- color: rgb(var(--color-error, 247 118 142));
202
- background: rgb(var(--color-error, 247 118 142) / 12%);
208
+ color: var(
209
+ --hi-icon-button-icon-color-active,
210
+ rgb(var(--color-error, 247 118 142))
211
+ );
212
+ background: var(
213
+ --hi-icon-button-bg-hover,
214
+ rgb(var(--color-error, 247 118 142) / 12%)
215
+ );
203
216
  }
204
217
  }
205
218
 
@@ -95,6 +95,11 @@
95
95
  }
96
96
 
97
97
  .hk-dp-clear {
98
+ /* Wave B1 hybrid decision (see HkSearchInput's twin): tabindex=-1 + own
99
+ keydown stop-propagation = stays a BARE button, pinned by
100
+ `date_clear_stays_a_bare_button_by_contract`. The reveal-on-hover
101
+ mechanism is the field's own contract and stays. What standardizes is
102
+ the INK via the icon-button channel vars (zero visual change). */
98
103
  appearance: none;
99
104
  display: inline-flex;
100
105
  align-items: center;
@@ -104,7 +109,7 @@
104
109
  border: 0;
105
110
  background: transparent;
106
111
  border-radius: var(--radius-sm, 4px);
107
- color: var(--hi-color-muted);
112
+ color: var(--hi-icon-button-icon-color, var(--hi-color-muted));
108
113
  cursor: pointer;
109
114
  opacity: 0;
110
115
  transition: opacity var(--duration-fast, 0.15s) ease, color var(--duration-fast, 0.15s) ease;
@@ -116,7 +121,7 @@
116
121
  }
117
122
 
118
123
  &:hover {
119
- color: var(--hi-color-text-primary);
124
+ color: var(--hi-icon-button-icon-color-active, var(--hi-color-text-primary));
120
125
  }
121
126
  }
122
127
 
@@ -98,28 +98,10 @@
98
98
  }
99
99
 
100
100
  .hk-file-clear {
101
+ /* The clear affordance is the STANDARD icon button (wave B1): S24 exactly
102
+ replaces the old 1.5rem box; box, ink, hover and focus come from the
103
+ component. The seat keeps only its flex slot in the trigger row. */
101
104
  flex-shrink: 0;
102
- display: inline-flex;
103
- align-items: center;
104
- justify-content: center;
105
- width: 1.5rem;
106
- height: 1.5rem;
107
- padding: 0;
108
- background: transparent;
109
- border: 0;
110
- border-radius: var(--radius-xs, 2px);
111
- color: rgb(var(--color-text) / 55%);
112
- cursor: pointer;
113
-
114
- &:hover {
115
- background: rgb(var(--color-text) / 8%);
116
- color: rgb(var(--color-text));
117
- }
118
-
119
- &:focus-visible {
120
- outline: 2px solid var(--hi-color-primary, #7aa2f7);
121
- outline-offset: 1px;
122
- }
123
105
  }
124
106
 
125
107
  /* The native input stays in the DOM for the trigger to click, but is
@@ -1,3 +1,7 @@
1
+ import { X } from "lucide-vue-next";
2
+
3
+ import HkIconButton from "./HkIconButton";
4
+
1
5
  import { computed, defineComponent, ref, useId, watch } from "vue";
2
6
 
3
7
  import { useI18n } from "../i18n/context";
@@ -170,26 +174,15 @@ export default defineComponent({
170
174
  </span>
171
175
  </button>
172
176
  {files.length > 0 && !props.disabled && (
173
- <button
174
- type="button"
177
+ <HkIconButton
175
178
  class="hk-file-clear"
179
+ size={24}
180
+ variant="ghost"
176
181
  aria-label={t("hikari::filePicker.fieldClear", "Clear selection")}
177
182
  onClick={clear}
178
183
  >
179
- <svg
180
- viewBox="0 0 24 24"
181
- fill="none"
182
- stroke="currentColor"
183
- stroke-width="2"
184
- stroke-linecap="round"
185
- width="14"
186
- height="14"
187
- aria-hidden="true"
188
- >
189
- <line x1="18" y1="6" x2="6" y2="18" />
190
- <line x1="6" y1="6" x2="18" y2="18" />
191
- </svg>
192
- </button>
184
+ {{ icon: () => <X aria-hidden="true" /> }}
185
+ </HkIconButton>
193
186
  )}
194
187
  {props.mode === "local" && (
195
188
  <input
@@ -83,33 +83,23 @@
83
83
  }
84
84
 
85
85
  .hk-filter-panel-op {
86
+ /* Wave B2: the operator toggles are STANDARD icon buttons at the S28 rung
87
+ (the old 1.75rem box). The pressed operator's persistent primary tint
88
+ rides the seat's channel overrides, scoped to [aria-pressed="true"];
89
+ font-weight stays a seat concern (the component carries no text). */
86
90
  flex: 0 0 auto;
87
91
  scroll-snap-align: center;
88
- min-width: 1.75rem;
89
- height: 1.75rem;
90
- padding: 0 var(--space-6, 0.375rem);
91
- display: inline-flex;
92
- align-items: center;
93
- justify-content: center;
94
- border: none;
95
- border-radius: var(--radius-sm, 6px);
96
- background: transparent;
97
- color: rgb(var(--color-muted, var(--color-text-secondary)));
98
- font-size: var(--text-sm, 0.875rem);
99
- line-height: 1;
100
- cursor: pointer;
101
- transition: background 0.15s ease, color 0.15s ease;
102
- }
103
92
 
104
- .hk-filter-panel-op:hover {
105
- background: rgb(var(--color-primary) / 12%);
106
- color: rgb(var(--color-text));
107
- }
108
-
109
- .hk-filter-panel-op[aria-pressed="true"] {
110
- background: rgb(var(--color-primary) / 18%);
111
- color: rgb(var(--color-primary));
112
- font-weight: 700;
93
+ &[aria-pressed="true"] {
94
+ --hi-icon-button-bg: rgb(var(--color-primary) / 18%);
95
+ --hi-icon-button-icon-color: rgb(var(--color-primary));
96
+ --hi-icon-button-icon-color-active: rgb(var(--color-primary));
97
+ /* Keep the primary tint THROUGH hover (the old file-order cascade
98
+ did): without this the pressed op falls back to the ghost gray-20
99
+ hover wash and reads un-pressed under the pointer. */
100
+ --hi-icon-button-bg-hover: rgb(var(--color-primary) / 18%);
101
+ font-weight: 700;
102
+ }
113
103
  }
114
104
 
115
105
  .hk-filter-panel-op:disabled {
@@ -133,28 +123,16 @@
133
123
  }
134
124
 
135
125
  .hk-filter-panel-remove {
126
+ /* Wave B2: the condition remove is the STANDARD icon button (S24 = the
127
+ old 1.5rem box). The error-tinted hover rides the channel vars — ink
128
+ hover-scoped (the token-input lesson: a rest-scoped ink var reads at
129
+ rest); the standard layer owns disabled presentation. */
136
130
  flex: 0 0 auto;
137
- width: 1.5rem;
138
- height: 1.5rem;
139
- display: inline-flex;
140
- align-items: center;
141
- justify-content: center;
142
- border: none;
143
- border-radius: var(--radius-sm, 6px);
144
- background: transparent;
145
- color: rgb(var(--color-muted, var(--color-text-secondary)));
146
- cursor: pointer;
147
- transition: background 0.15s ease, color 0.15s ease;
148
- }
149
-
150
- .hk-filter-panel-remove:hover {
151
- background: rgb(var(--color-error) / 12%);
152
- color: rgb(var(--color-error));
153
- }
131
+ --hi-icon-button-bg-hover: rgb(var(--color-error) / 12%);
154
132
 
155
- .hk-filter-panel-remove:disabled {
156
- opacity: 0.5;
157
- cursor: not-allowed;
133
+ &:hover {
134
+ --hi-icon-button-icon-color: rgb(var(--color-error));
135
+ }
158
136
  }
159
137
 
160
138
  /* The growth verb: parked in the OPERATOR COLUMN (grid-column 2), so it
@@ -1,3 +1,5 @@
1
+ import HkIconButton from "./HkIconButton";
2
+
1
3
  import { computed, defineComponent, nextTick, ref, watch, type PropType } from "vue";
2
4
  import { Plus, X } from "lucide-vue-next";
3
5
 
@@ -325,18 +327,19 @@ export default defineComponent({
325
327
  {ops.map((op) => {
326
328
  const glyph = glyphOpFor(kind, op);
327
329
  return (
328
- <button
330
+ <HkIconButton
329
331
  key={op}
330
- type="button"
331
332
  class="hk-filter-panel-op"
333
+ size={28}
334
+ variant="ghost"
332
335
  aria-pressed={cond.op === op}
333
336
  aria-label={t(OPERATOR_LABEL[glyph].key, OPERATOR_LABEL[glyph].fallback)}
334
- title={t(OPERATOR_LABEL[glyph].key, OPERATOR_LABEL[glyph].fallback)}
337
+ {...{ title: t(OPERATOR_LABEL[glyph].key, OPERATOR_LABEL[glyph].fallback) }}
335
338
  disabled={props.disabled || !field}
336
339
  onClick={() => emitCondition(index, { op })}
337
340
  >
338
- <HkFilterOperatorIcon op={glyph} />
339
- </button>
341
+ {{ icon: () => <HkFilterOperatorIcon op={glyph} /> }}
342
+ </HkIconButton>
340
343
  );
341
344
  })}
342
345
  </div>
@@ -394,19 +397,20 @@ export default defineComponent({
394
397
  * page refetches without it). Sibling conditions on
395
398
  * the same field survive — index-targeted removal,
396
399
  * never key-targeted. */}
397
- <button
398
- type="button"
400
+ <HkIconButton
399
401
  class="hk-filter-panel-remove"
402
+ size={24}
403
+ variant="ghost"
400
404
  aria-label={t("hikari::filterPanel.removeCondition", "Remove condition")}
401
- title={t("hikari::filterPanel.removeCondition", "Remove condition")}
405
+ {...{ title: t("hikari::filterPanel.removeCondition", "Remove condition") }}
402
406
  disabled={props.disabled}
403
407
  onClick={() => {
404
408
  const next = props.modelValue.filter((_, i) => i !== index);
405
409
  emit("update:modelValue", next);
406
410
  }}
407
411
  >
408
- <X size={14} aria-hidden="true" />
409
- </button>
412
+ {{ icon: () => <X aria-hidden="true" /> }}
413
+ </HkIconButton>
410
414
  </div>
411
415
  </div>
412
416
  );
@@ -41,23 +41,10 @@
41
41
  }
42
42
 
43
43
  .hk-kw-search-clear {
44
- appearance: none;
45
- background: transparent;
46
- border: 0;
47
- color: var(--hi-color-text-secondary, #666666);
48
- cursor: pointer;
49
- display: inline-flex;
44
+ /* Wave B2/B3: the clear affordance is the STANDARD icon button — box,
45
+ ink, hover and focus come from the component; the seat keeps only the
46
+ field's inner padding slot. */
50
47
  padding: var(--space-2, 0.125rem);
51
- border-radius: var(--radius-sm, 0.25rem);
52
-
53
- &:hover {
54
- color: var(--hi-color-text-primary, #1e1e1e);
55
- }
56
-
57
- &:focus-visible {
58
- outline: 2px solid color-mix(in srgb, var(--hi-color-primary, #7aa2f7) 55%, transparent);
59
- outline-offset: 2px;
60
- }
61
48
  }
62
49
 
63
50
  /* ONE SCROLLBAR PER WINDOW (2026-09-08 audit): the results list is NOT a
@@ -1,3 +1,5 @@
1
+ import HkIconButton from "./HkIconButton";
2
+
1
3
  import { computed, defineComponent, onBeforeUnmount, ref, watch, type PropType } from "vue";
2
4
 
3
5
  import { useI18n } from "../i18n/context";
@@ -241,9 +243,10 @@ export default defineComponent({
241
243
  autofocus
242
244
  />
243
245
  {query.value && (
244
- <button
246
+ <HkIconButton
245
247
  class="hk-kw-search-clear"
246
- type="button"
248
+ size={24}
249
+ variant="ghost"
247
250
  aria-label={t("hikari::keywordSearch.clear", "Clear")}
248
251
  onClick={() => {
249
252
  query.value = "";
@@ -251,19 +254,21 @@ export default defineComponent({
251
254
  semanticResults.value = [];
252
255
  }}
253
256
  >
254
- <svg
255
- width="14"
256
- height="14"
257
- viewBox="0 0 24 24"
258
- fill="none"
259
- stroke="currentColor"
260
- stroke-width="2"
261
- stroke-linecap="round"
262
- >
263
- <line x1="18" y1="6" x2="6" y2="18" />
264
- <line x1="6" y1="6" x2="18" y2="18" />
265
- </svg>
266
- </button>
257
+ {{ icon: () => (
258
+ <svg
259
+ width="14"
260
+ height="14"
261
+ viewBox="0 0 24 24"
262
+ fill="none"
263
+ stroke="currentColor"
264
+ stroke-width="2"
265
+ stroke-linecap="round"
266
+ >
267
+ <line x1="18" y1="6" x2="6" y2="18" />
268
+ <line x1="6" y1="6" x2="18" y2="18" />
269
+ </svg>
270
+ ) }}
271
+ </HkIconButton>
267
272
  )}
268
273
  </div>
269
274