diff --git a/website/scripts/panes/chart/index.js b/website/scripts/panes/chart/index.js index 5386a8d02..36ab211a3 100644 --- a/website/scripts/panes/chart/index.js +++ b/website/scripts/panes/chart/index.js @@ -469,7 +469,16 @@ function createIndexSelector(option, state) { ); }); - // Create UI that syncs with state.index + /** @type {ChartableIndexName} */ + const defaultIndex = "date"; + const { field } = createChoiceField({ + defaultValue: defaultIndex, + signal: state.index, + choices, + id: "index", + signals, + }); + const fieldset = window.document.createElement("fieldset"); fieldset.id = "interval"; @@ -477,33 +486,9 @@ function createIndexSelector(option, state) { screenshotSpan.innerText = "interval:"; fieldset.append(screenshotSpan); - const select = window.document.createElement("select"); - select.id = "index"; - fieldset.append(select); + fieldset.append(field); fieldset.dataset.size = "sm"; - // Populate and update options when choices change - signals.createEffect(choices, (choices) => { - const currentValue = state.index(); - select.innerHTML = ""; - choices.forEach((choice) => { - const option = window.document.createElement("option"); - option.value = choice; - option.textContent = choice; - option.selected = choice === currentValue; - select.append(option); - }); - }); - - // Sync select value with state - signals.createEffect(state.index, (value) => { - select.value = value; - }); - - select.addEventListener("change", () => { - state.index.set(/** @type {ChartableIndexName} */ (select.value)); - }); - // Convert short name to internal name const index = signals.createMemo(() => serdeChartableIndex.deserialize(state.index()), diff --git a/website/scripts/utils/dom.js b/website/scripts/utils/dom.js index 546f06200..dd41958fd 100644 --- a/website/scripts/utils/dom.js +++ b/website/scripts/utils/dom.js @@ -219,9 +219,10 @@ export function importStyle(href) { * @param {string} [args.id] * @param {readonly T[] | Accessor} args.choices * @param {string} [args.keyPrefix] - * @param {string} args.key + * @param {string} [args.key] * @param {boolean} [args.sorted] * @param {Signals} args.signals + * @param {Signal} [args.signal] - Optional external signal to use instead of creating one * @param {(choice: T) => string} [args.toKey] - Extract string key for storage (defaults to identity for strings) * @param {(choice: T) => string} [args.toLabel] - Extract display label (defaults to identity for strings) * @param {"radio" | "select"} [args.type] - Render as radio buttons or select dropdown @@ -233,6 +234,7 @@ export function createChoiceField({ keyPrefix, key, signals, + signal: externalSignal, sorted, toKey = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c), toLabel = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c), @@ -268,12 +270,12 @@ export function createChoiceField({ } /** @type {Signal} */ - const selected = signals.createSignal(defaultValue, { + const selected = externalSignal ?? signals.createSignal(defaultValue, { save: { serialize: (v) => toKey(v), deserialize: (s) => fromKey(s), keyPrefix: keyPrefix ?? "", - key, + key: key ?? "", saveDefaultValue: true, }, });