@cosmicdrift/kumiko-renderer-web 0.55.0 → 0.55.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer-web",
3
- "version": "0.55.0",
3
+ "version": "0.55.1",
4
4
  "description": "Web-platform bindings for @cosmicdrift/kumiko-renderer. HTML default-primitives, browser history-based navigation, EventSource-backed live events, and a one-call createKumikoApp that mounts the whole stack via react-dom.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -219,10 +219,12 @@ describe("KumikoScreen / configEdit", () => {
219
219
  await waitFor(() =>
220
220
  expect(field.querySelectorAll('[data-testid="config-cascade"]')).toHaveLength(1),
221
221
  );
222
- expect(field.querySelectorAll('[data-testid="config-source-badge"]')).toHaveLength(1);
223
- // Badge inline am Label, Disclosure unter dem Input nicht umgekehrt.
222
+ // Eine einzige Status-Stelle pro Feld: die Cascade-Disclosure unter dem
223
+ // Input trägt Quelle + Wert. Das frühere Label-Badge war redundant und
224
+ // wurde entfernt (User-Feedback "2× Fehlt").
225
+ expect(field.querySelectorAll('[data-testid="config-source-badge"]')).toHaveLength(0);
224
226
  const label = field.querySelector("label");
225
- expect(label?.querySelector('[data-testid="config-source-badge"]')).toBeTruthy();
227
+ expect(label?.querySelector('[data-testid="config-source-badge"]')).toBeNull();
226
228
  expect(label?.querySelector('[data-testid="config-cascade"]')).toBeNull();
227
229
  });
228
230
  });
@@ -11,8 +11,8 @@
11
11
 
12
12
  import * as PopoverPrimitive from "@radix-ui/react-popover";
13
13
  import { Calendar as CalendarIcon } from "lucide-react";
14
- import type { ReactNode } from "react";
15
- import { DayPicker } from "react-day-picker";
14
+ import type { ReactElement, ReactNode } from "react";
15
+ import { DayPicker, type DropdownProps } from "react-day-picker";
16
16
  import { cn } from "../lib/cn";
17
17
 
18
18
  export type CalendarPopoverProps = {
@@ -89,6 +89,7 @@ export function CalendarPopover({
89
89
  {...(disabledMatchers.length > 0 && { disabled: disabledMatchers })}
90
90
  onSelect={(d) => onSelect(d)}
91
91
  classNames={dayPickerClasses}
92
+ components={{ Dropdown: SelectDropdown }}
92
93
  />
93
94
  </PopoverPrimitive.Content>
94
95
  </PopoverPrimitive.Portal>
@@ -96,20 +97,45 @@ export function CalendarPopover({
96
97
  );
97
98
  }
98
99
 
100
+ const dropdownSelectClass =
101
+ "rounded-sm border border-input bg-transparent px-1.5 py-0.5 text-sm font-medium " +
102
+ "cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
103
+
104
+ // rdp v9s Default-Dropdown rendert NEBEN dem <select> ein aria-hidden
105
+ // <span> mit demselben Label — sichtbar nur, wenn rdps eigene style.css
106
+ // das <select> transparent darüberlegt. Da wir die rdp-Klassen mit eigenen
107
+ // Tokens überschreiben, greift diese Positionierung nicht → Label doppelt
108
+ // (#369-Folgebug). Ein nacktes <select> ohne Begleit-Span vermeidet das
109
+ // CSS-unabhängig — eine Quelle für den sichtbaren Wert.
110
+ function SelectDropdown({
111
+ options,
112
+ className,
113
+ // components/classNames reicht rdp mit durch — keine validen <select>-
114
+ // Attribute, daher hier rausgezogen statt mitzuspreaden.
115
+ components: _components,
116
+ classNames: _classNames,
117
+ ...selectProps
118
+ }: DropdownProps): ReactElement {
119
+ return (
120
+ <select className={cn(dropdownSelectClass, className)} {...selectProps}>
121
+ {options?.map((opt) => (
122
+ <option key={opt.value} value={opt.value} disabled={opt.disabled}>
123
+ {opt.label}
124
+ </option>
125
+ ))}
126
+ </select>
127
+ );
128
+ }
129
+
99
130
  // classNames-Map für react-day-picker v9 — überschreibt die default-
100
- // Klassen mit Tailwind/shadcn-Tokens. dropdowns/dropdown decken den
101
- // captionLayout="dropdown"-Modus ab (Monat-/Jahr-Selects).
131
+ // Klassen mit Tailwind/shadcn-Tokens. Die Monat-/Jahr-Selects rendert
132
+ // SelectDropdown (components-Prop), daher hier nur der dropdowns-Container.
102
133
  const dayPickerClasses = {
103
134
  root: "rdp-root",
104
135
  months: "flex flex-col gap-2",
105
136
  month: "flex flex-col gap-2",
106
137
  month_caption: "flex justify-center items-center h-7 text-sm font-medium",
107
- caption_label: "text-sm font-medium",
108
138
  dropdowns: "flex items-center gap-1 text-sm font-medium",
109
- dropdown_root: "relative inline-flex items-center",
110
- dropdown:
111
- "rounded-sm border border-input bg-transparent px-1.5 py-0.5 text-sm " +
112
- "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
113
139
  nav: "flex items-center gap-1 absolute right-1 top-2",
114
140
  button_previous: "inline-flex h-7 w-7 items-center justify-center rounded-sm hover:bg-accent",
115
141
  button_next: "inline-flex h-7 w-7 items-center justify-center rounded-sm hover:bg-accent",