@fusion.dev/helix 0.12.3 → 0.13.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/types/jsx.d.ts CHANGED
@@ -59,6 +59,7 @@ import type {
59
59
  HelixEmpty,
60
60
  HelixFileInput,
61
61
  HelixFilterEvent,
62
+ HelixFilterInput,
62
63
  HelixFlex,
63
64
  HelixFormatDate,
64
65
  HelixGrid,
@@ -4045,6 +4046,9 @@ export type HelixComboboxHelixBeforeOpenElementEvent =
4045
4046
  /** `helix-create` event type */
4046
4047
  export type HelixComboboxHelixCreateElementEvent =
4047
4048
  HelixComboboxElementEvent<HelixCreateEvent>;
4049
+ /** `helix-filter` event type */
4050
+ export type HelixComboboxHelixFilterElementEvent =
4051
+ HelixComboboxElementEvent<HelixFilterEvent>;
4048
4052
 
4049
4053
  export type HelixComboboxProps = {
4050
4054
  /** Whether the element is open.
@@ -4194,6 +4198,8 @@ differently: they are one chooser to a consumer. */
4194
4198
  "onhelix-before-open"?: ((e: HelixComboboxHelixBeforeOpenElementEvent) => void) | undefined;
4195
4199
  /** Fired when the reader asks for something the list does not hold, and cancelable. */
4196
4200
  "onhelix-create"?: ((e: HelixComboboxHelixCreateElementEvent) => void) | undefined;
4201
+ /** Fired as the reader types, carrying the text the list is being narrowed to. Cancelable: refusing it leaves the list whole, and is how a consumer takes the filtering for themselves. */
4202
+ "onhelix-filter"?: ((e: HelixComboboxHelixFilterElementEvent) => void) | undefined;
4197
4203
  /** Says the state moved, carrying `newState` and `oldState`. */
4198
4204
  ontoggle?: ((e: HelixComboboxElementEvent) => void) | undefined;
4199
4205
  };
@@ -4347,6 +4353,8 @@ differently: they are one chooser to a consumer. */
4347
4353
  ) => void) | undefined;
4348
4354
  /** Fired when the reader asks for something the list does not hold, and cancelable. */
4349
4355
  "on:helix-create"?: ((e: HelixComboboxHelixCreateElementEvent) => void) | undefined;
4356
+ /** Fired as the reader types, carrying the text the list is being narrowed to. Cancelable: refusing it leaves the list whole, and is how a consumer takes the filtering for themselves. */
4357
+ "on:helix-filter"?: ((e: HelixComboboxHelixFilterElementEvent) => void) | undefined;
4350
4358
  /** Says the state moved, carrying `newState` and `oldState`. */
4351
4359
  "on:toggle"?: ((e: HelixComboboxElementEvent) => void) | undefined;
4352
4360
 
@@ -6941,6 +6949,171 @@ Here rather than on each control. */
6941
6949
  textContent?: (string | number) | undefined;
6942
6950
  };
6943
6951
 
6952
+ /** `HelixFilterInput` component event */
6953
+ export type HelixFilterInputElementEvent<E = Event> = TypedEvent<
6954
+ HelixFilterInput,
6955
+ E
6956
+ >;
6957
+ /** `helix-before-change` event type */
6958
+ export type HelixFilterInputHelixBeforeChangeElementEvent =
6959
+ HelixFilterInputElementEvent<HelixBeforeChangeEvent>;
6960
+
6961
+ export type HelixFilterInputProps = {
6962
+ /** How many tokens to show before the rest become a count. */
6963
+ "max-tags"?: (HelixFilterInput["maxTags"]) | undefined;
6964
+ /** How many tokens to show before the rest become a count. */
6965
+ maxTags?: (HelixFilterInput["maxTags"]) | undefined;
6966
+ /** The value the markup declared, which is where a reset returns to. */
6967
+ "default-value"?: (HelixFilterInput["defaultValue"]) | undefined;
6968
+ /** The value the markup declared, which is where a reset returns to. */
6969
+ defaultValue?: (HelixFilterInput["defaultValue"]) | undefined;
6970
+ /** What the control holds now, and what its form submits.
6971
+
6972
+ One property, not two, so `input.value` answers the question anyone
6973
+ asking it meant. Writing always applies; `<helix-input value="x">` is the
6974
+ same statement in markup, and `default-value` is how markup seeds a value
6975
+ a reset should return to. */
6976
+ value?: (HelixFilterInput["value"]) | undefined;
6977
+ /** What is wrong, in the reader's words rather than the browser's. */
6978
+ feedback?: (HelixFilterInput["feedback"]) | undefined;
6979
+ /** Help under the control, shown while there is nothing wrong. */
6980
+ hint?: (HelixFilterInput["hint"]) | undefined;
6981
+ /** The accessible name, and the fallback for the `label` slot. */
6982
+ label?: (HelixFilterInput["label"]) | undefined;
6983
+ /** Whether the form refuses to submit without it. */
6984
+ required?: (HelixFilterInput["required"]) | undefined;
6985
+ /** Whether the field offers a button that empties it.
6986
+
6987
+ The text only. The tokens are the consumer's markup and this element is not
6988
+ entitled to take them out of the document, which is the same reason
6989
+ `hideOverflow` marks the ones over the cap `hidden` rather than removing
6990
+ them. */
6991
+ clearable?: (HelixFilterInput["clearable"]) | undefined;
6992
+ /** What the clear button is called, since an icon has no name of its own. */
6993
+ "clear-label"?: (HelixFilterInput["clearLabel"]) | undefined;
6994
+ /** What the clear button is called, since an icon has no name of its own. */
6995
+ clearLabel?: (HelixFilterInput["clearLabel"]) | undefined;
6996
+ /** Shown while the field is empty.
6997
+
6998
+ Not a label: it goes when typing starts. */
6999
+ placeholder?: (HelixFilterInput["placeholder"]) | undefined;
7000
+ /** Whether the control is non-interactive.
7001
+
7002
+ Reflected, because the styled tier selects on it, and mirrored to
7003
+ `aria-disabled` rather than removing the element from the accessibility
7004
+ tree, so a screen reader can still announce that the control exists.
7005
+
7006
+ The mirror itself is in `willUpdate` below, here rather than in each
7007
+ control, because here is where `disabled` is. */
7008
+ disabled?: (HelixFilterInput["disabled"]) | undefined;
7009
+ /** Name submitted with the form.
7010
+
7011
+ **Reflected, and it is the exception to "reflect only what CSS selects
7012
+ on".** The platform builds a form's entry list from the `name` *content
7013
+ attribute*, not from the property, so a control named through the property
7014
+ submitted under no name at all and was silently dropped. Measured: two
7015
+ inputs in one form, one named by attribute and one by property, and the
7016
+ form carried a single entry.
7017
+
7018
+ Safe for a React consumer, which is what the rule is protecting: React
7019
+ renders a custom element's props as attributes on the server, so the name
7020
+ is already in the markup being hydrated and reflecting it writes what is
7021
+ there. It is only a change to the markup when a consumer assigns it
7022
+ imperatively later, and nothing is hydrating by then.
7023
+
7024
+ Here rather than on each control. */
7025
+ name?: (HelixFilterInput["name"]) | undefined;
7026
+
7027
+ /** Announced once the text has moved. */
7028
+ oninput?: ((e: HelixFilterInputElementEvent) => void) | undefined;
7029
+ /** Relayed from the input once the reader has finished. */
7030
+ onchange?: ((e: HelixFilterInputElementEvent) => void) | undefined;
7031
+ /** Fired as the text changes, and cancelable. */
7032
+ "onhelix-before-change"?: ((
7033
+ e: HelixFilterInputHelixBeforeChangeElementEvent,
7034
+ ) => void) | undefined;
7035
+ };
7036
+
7037
+ export type HelixFilterInputSolidJsProps = {
7038
+ /** How many tokens to show before the rest become a count. */
7039
+ "attr:max-tags"?: (HelixFilterInput["maxTags"]) | undefined;
7040
+ /** How many tokens to show before the rest become a count. */
7041
+ "prop:maxTags"?: (HelixFilterInput["maxTags"]) | undefined;
7042
+ /** The value the markup declared, which is where a reset returns to. */
7043
+ "attr:default-value"?: (HelixFilterInput["defaultValue"]) | undefined;
7044
+ /** The value the markup declared, which is where a reset returns to. */
7045
+ "prop:defaultValue"?: (HelixFilterInput["defaultValue"]) | undefined;
7046
+ /** What the control holds now, and what its form submits.
7047
+
7048
+ One property, not two, so `input.value` answers the question anyone
7049
+ asking it meant. Writing always applies; `<helix-input value="x">` is the
7050
+ same statement in markup, and `default-value` is how markup seeds a value
7051
+ a reset should return to. */
7052
+ "prop:value"?: (HelixFilterInput["value"]) | undefined;
7053
+ /** What is wrong, in the reader's words rather than the browser's. */
7054
+ "prop:feedback"?: (HelixFilterInput["feedback"]) | undefined;
7055
+ /** Help under the control, shown while there is nothing wrong. */
7056
+ "prop:hint"?: (HelixFilterInput["hint"]) | undefined;
7057
+ /** The accessible name, and the fallback for the `label` slot. */
7058
+ "prop:label"?: (HelixFilterInput["label"]) | undefined;
7059
+ /** Whether the form refuses to submit without it. */
7060
+ "prop:required"?: (HelixFilterInput["required"]) | undefined;
7061
+ /** Whether the field offers a button that empties it.
7062
+
7063
+ The text only. The tokens are the consumer's markup and this element is not
7064
+ entitled to take them out of the document, which is the same reason
7065
+ `hideOverflow` marks the ones over the cap `hidden` rather than removing
7066
+ them. */
7067
+ "prop:clearable"?: (HelixFilterInput["clearable"]) | undefined;
7068
+ /** What the clear button is called, since an icon has no name of its own. */
7069
+ "attr:clear-label"?: (HelixFilterInput["clearLabel"]) | undefined;
7070
+ /** What the clear button is called, since an icon has no name of its own. */
7071
+ "prop:clearLabel"?: (HelixFilterInput["clearLabel"]) | undefined;
7072
+ /** Shown while the field is empty.
7073
+
7074
+ Not a label: it goes when typing starts. */
7075
+ "prop:placeholder"?: (HelixFilterInput["placeholder"]) | undefined;
7076
+ /** Whether the control is non-interactive.
7077
+
7078
+ Reflected, because the styled tier selects on it, and mirrored to
7079
+ `aria-disabled` rather than removing the element from the accessibility
7080
+ tree, so a screen reader can still announce that the control exists.
7081
+
7082
+ The mirror itself is in `willUpdate` below, here rather than in each
7083
+ control, because here is where `disabled` is. */
7084
+ "prop:disabled"?: (HelixFilterInput["disabled"]) | undefined;
7085
+ /** Name submitted with the form.
7086
+
7087
+ **Reflected, and it is the exception to "reflect only what CSS selects
7088
+ on".** The platform builds a form's entry list from the `name` *content
7089
+ attribute*, not from the property, so a control named through the property
7090
+ submitted under no name at all and was silently dropped. Measured: two
7091
+ inputs in one form, one named by attribute and one by property, and the
7092
+ form carried a single entry.
7093
+
7094
+ Safe for a React consumer, which is what the rule is protecting: React
7095
+ renders a custom element's props as attributes on the server, so the name
7096
+ is already in the markup being hydrated and reflecting it writes what is
7097
+ there. It is only a change to the markup when a consumer assigns it
7098
+ imperatively later, and nothing is hydrating by then.
7099
+
7100
+ Here rather than on each control. */
7101
+ "prop:name"?: (HelixFilterInput["name"]) | undefined;
7102
+ /** Announced once the text has moved. */
7103
+ "on:input"?: ((e: HelixFilterInputElementEvent) => void) | undefined;
7104
+ /** Relayed from the input once the reader has finished. */
7105
+ "on:change"?: ((e: HelixFilterInputElementEvent) => void) | undefined;
7106
+ /** Fired as the text changes, and cancelable. */
7107
+ "on:helix-before-change"?: ((
7108
+ e: HelixFilterInputHelixBeforeChangeElementEvent,
7109
+ ) => void) | undefined;
7110
+
7111
+ /** Set the innerHTML of the element */
7112
+ innerHTML?: (string) | undefined;
7113
+ /** Set the textContent of the element */
7114
+ textContent?: (string | number) | undefined;
7115
+ };
7116
+
6944
7117
  export type HelixFlexProps = {
6945
7118
  /** Alignment across the direction. */
6946
7119
  align?: (HelixFlex["align"]) | undefined;
@@ -21361,6 +21534,7 @@ export type CustomElements = {
21361
21534
  * - `helix-before-close`: Fired before it closes. Cancelable: refusing it takes the decision and nothing moves.
21362
21535
  * - `helix-before-open`: Fired before the panel opens. Cancelable: refusing it takes the decision and nothing moves.
21363
21536
  * - `helix-create`: Fired when the reader asks for something the list does not hold, and cancelable.
21537
+ * - `helix-filter`: Fired as the reader types, carrying the text the list is being narrowed to. Cancelable: refusing it leaves the list whole, and is how a consumer takes the filtering for themselves.
21364
21538
  * - `toggle`: Says the state moved, carrying `newState` and `oldState`.
21365
21539
  *
21366
21540
  * ## Slots
@@ -23529,6 +23703,187 @@ export type CustomElements = {
23529
23703
  HelixFileInputProps & BaseProps<HelixFileInput> & BaseEvents<HelixFileInput>
23530
23704
  >;
23531
23705
 
23706
+ /**
23707
+ * The frame is the field rather than the input, so the tokens sit inside the
23708
+ * same box as the text and the focus ring is drawn once around the whole
23709
+ * control. It grows down a line at a time as tokens are added, which is the
23710
+ * arrangement Combobox takes when it is holding a selection.
23711
+ *
23712
+ * **The tokens are the consumer's own elements**, so the only thing said about
23713
+ * them here is to keep their size and not run past the field. A `Tag` slotted
23714
+ * into `tags` already looks like one; anything else looks like whatever it is.
23715
+ *
23716
+ * Height comes from the region, like every other control: `data-density` on
23717
+ * whatever holds it, not a `size` here.
23718
+ *
23719
+ * ## Attributes & Properties
23720
+ *
23721
+ * Component attributes and properties that can be applied to the element or by using JavaScript.
23722
+ *
23723
+ * - `max-tags`/`maxTags`: How many tokens to show before the rest become a count.
23724
+ * - `default-value`/`defaultValue`: The value the markup declared, which is where a reset returns to.
23725
+ * - `value`: What the control holds now, and what its form submits.
23726
+ *
23727
+ * One property, not two, so `input.value` answers the question anyone
23728
+ * asking it meant. Writing always applies; `<helix-input value="x">` is the
23729
+ * same statement in markup, and `default-value` is how markup seeds a value
23730
+ * a reset should return to.
23731
+ * - `feedback`: What is wrong, in the reader's words rather than the browser's.
23732
+ * - `hint`: Help under the control, shown while there is nothing wrong.
23733
+ * - `label`: The accessible name, and the fallback for the `label` slot.
23734
+ * - `required`: Whether the form refuses to submit without it.
23735
+ * - `clearable`: Whether the field offers a button that empties it.
23736
+ *
23737
+ * The text only. The tokens are the consumer's markup and this element is not
23738
+ * entitled to take them out of the document, which is the same reason
23739
+ * `hideOverflow` marks the ones over the cap `hidden` rather than removing
23740
+ * them.
23741
+ * - `clear-label`/`clearLabel`: What the clear button is called, since an icon has no name of its own.
23742
+ * - `placeholder`: Shown while the field is empty.
23743
+ *
23744
+ * Not a label: it goes when typing starts.
23745
+ * - `disabled`: Whether the control is non-interactive.
23746
+ *
23747
+ * Reflected, because the styled tier selects on it, and mirrored to
23748
+ * `aria-disabled` rather than removing the element from the accessibility
23749
+ * tree, so a screen reader can still announce that the control exists.
23750
+ *
23751
+ * The mirror itself is in `willUpdate` below, here rather than in each
23752
+ * control, because here is where `disabled` is.
23753
+ * - `name`: Name submitted with the form.
23754
+ *
23755
+ * **Reflected, and it is the exception to "reflect only what CSS selects
23756
+ * on".** The platform builds a form's entry list from the `name` *content
23757
+ * attribute*, not from the property, so a control named through the property
23758
+ * submitted under no name at all and was silently dropped. Measured: two
23759
+ * inputs in one form, one named by attribute and one by property, and the
23760
+ * form carried a single entry.
23761
+ *
23762
+ * Safe for a React consumer, which is what the rule is protecting: React
23763
+ * renders a custom element's props as attributes on the server, so the name
23764
+ * is already in the markup being hydrated and reflecting it writes what is
23765
+ * there. It is only a change to the markup when a consumer assigns it
23766
+ * imperatively later, and nothing is hydrating by then.
23767
+ *
23768
+ * Here rather than on each control.
23769
+ * - `form`: The form this control belongs to, if any. (property only) (readonly)
23770
+ * - `labels`: Labels associated with this control. (property only) (readonly)
23771
+ * - `whenSettled`: Resolves a frame after the first update, when transitions are switched on.
23772
+ *
23773
+ * **Named `whenSettled` because `settled` is taken four times over**, by
23774
+ * Image, Splitter and both color controls, none of them about transitions. A
23775
+ * base class takes the name every subclass then cannot use.
23776
+ *
23777
+ * **The state it reports cannot be watched, which is why this exists.** A
23778
+ * custom state is deliberately not in the DOM, so there is no
23779
+ * `MutationObserver` equivalent for `ElementInternals.states`. Await this
23780
+ * instead.
23781
+ *
23782
+ * Separate from `updateComplete`, which resolves in the microtask checkpoint
23783
+ * the suppression is still active in. That is the distinction `readyToMove`
23784
+ * in `@fusion.dev/helix-testing` is written around.
23785
+ *
23786
+ * It never resolves where `requestAnimationFrame` never fires, which is a
23787
+ * server, a hidden tab, and happy-dom. Callers that must not hang race it
23788
+ * against a timeout; `readyToMove` does exactly that. (property only) (readonly)
23789
+ *
23790
+ * ## Events
23791
+ *
23792
+ * Events that will be emitted by the component.
23793
+ *
23794
+ * - `input`: Announced once the text has moved.
23795
+ * - `change`: Relayed from the input once the reader has finished.
23796
+ * - `helix-before-change`: Fired as the text changes, and cancelable.
23797
+ *
23798
+ * ## Slots
23799
+ *
23800
+ * Areas where markup can be added to the component.
23801
+ *
23802
+ * - `end`: After the text, for a count or a control.
23803
+ * - `start`: Before the text, for a search icon.
23804
+ * - `tags`: What is already narrowing the results, as `Tag`s.
23805
+ *
23806
+ * ## Methods
23807
+ *
23808
+ * Methods that can be called to access component functionality.
23809
+ *
23810
+ * - `requestValue(next: string) => boolean`: Requests a new value, and reports whether the request stood.
23811
+ *
23812
+ * Announces before it acts, so `preventDefault()` on the `helix-before-change` is
23813
+ * a refusal and nothing moves. Nobody refusing means the control updates
23814
+ * itself, whether or not a consumer declared `value`: a declared property
23815
+ * is a seed and a correction, the way `<input value>` is, and a consumer
23816
+ * who wants the change for themselves refuses it and assigns their own.
23817
+ * - `formResetCallback() => void`: Returns the control to the value its markup declared.
23818
+ *
23819
+ * Both halves are dropped, the consumer's and the control's, because a
23820
+ * reset means the form is as it was served. Clearing only the internal one
23821
+ * would leave a control that had been written to stuck at that value.
23822
+ * - `formStateRestoreCallback(state: string | null) => void`: Restores the value when the browser brings a form back.
23823
+ *
23824
+ * Falling back to `defaultValue` rather than to empty, because a restore
23825
+ * with no state is a form the browser has nothing recorded for, which is
23826
+ * the same situation as a fresh one.
23827
+ * - `focus(options?: FocusOptions) => void`: Puts the caret in the field, the way a label pointing at one would.
23828
+ * - `formDisabledCallback(disabled: boolean) => void`: The platform's notice that an ancestor fieldset changed.
23829
+ *
23830
+ * **The argument is the effective state, and taking it whole is what latched
23831
+ * every control in the library.** The platform calls this for the element's
23832
+ * own `disabled` as well as for a fieldset, and our own arrives here at the
23833
+ * worst possible moment: reflecting `disabled` to the attribute happens
23834
+ * inside Lit's `update()`, the UA fires this synchronously from that write,
23835
+ * and a reactive write during an update is a change-in-update Lit does not
23836
+ * re-render for. So `formDisabled` ran exactly one update behind forever.
23837
+ *
23838
+ * Measured on Slider, logging what `render` saw:
23839
+ *
23840
+ * ```
23841
+ * set true disabled true formDisabled false isDisabled true
23842
+ * set false disabled false formDisabled true isDisabled true <- stale
23843
+ * (no third render)
23844
+ * ```
23845
+ *
23846
+ * The host came out right every time, `disabled` false, `:disabled` not
23847
+ * matching, and the inner control kept the attribute, so a control disabled
23848
+ * once could never be re-enabled. It only shows when something re-enables,
23849
+ * which is the same shape of bug `inheritDisabled` was written for.
23850
+ *
23851
+ * Our own half is already in `this.disabled` and `isDisabled` is an or, so
23852
+ * this records only what the fieldset adds. That also removes the write
23853
+ * entirely on the own-disabled path rather than moving it.
23854
+ *
23855
+ * The one case this cannot see is a control that is disabled itself *and*
23856
+ * inside a disabled fieldset, whose own `disabled` is then removed: the
23857
+ * effective state does not change, so the platform does not call again, and
23858
+ * the fieldset's hold is not recorded. There is no callback to learn it from
23859
+ * and reading `:disabled` here would answer about the attribute we are in the
23860
+ * middle of removing.
23861
+ *
23862
+ * ## CSS Custom Properties
23863
+ *
23864
+ * CSS variables available for styling the component.
23865
+ *
23866
+ * - `--filter-input-background-color`: Fill behind the field. (default: `undefined`)
23867
+ * - `--filter-input-control-size`: Smallest the text keeps as tokens fill the line, before it wraps to its own. (default: `undefined`)
23868
+ * - `--filter-input-size`: Height of the field with nothing in it, which it grows from. (default: `undefined`)
23869
+ *
23870
+ * ## CSS Parts
23871
+ *
23872
+ * Custom selectors for styling elements within the component.
23873
+ *
23874
+ * - `clear`: The button that empties the field.
23875
+ * - `control`: The input itself.
23876
+ * - `feedback`: What is wrong with it.
23877
+ * - `field`: The box holding everything.
23878
+ * - `hint`: Help under the field, while nothing is wrong.
23879
+ * - `label`: The question, over the field.
23880
+ * - `rest`: How many tokens did not fit.
23881
+ * - `tags`: The row the tokens sit in.
23882
+ */
23883
+ "helix-filter-input": Partial<
23884
+ HelixFilterInputProps & BaseProps<HelixFilterInput> & BaseEvents<HelixFilterInput>
23885
+ >;
23886
+
23532
23887
  /**
23533
23888
  * The host is the flex container itself and the only child is a slot, so the
23534
23889
  * element adds no box of its own: `<helix-flex>` costs exactly the `<div>` it
@@ -37132,6 +37487,7 @@ export type CustomElementsSolidJs = {
37132
37487
  * - `helix-before-close`: Fired before it closes. Cancelable: refusing it takes the decision and nothing moves.
37133
37488
  * - `helix-before-open`: Fired before the panel opens. Cancelable: refusing it takes the decision and nothing moves.
37134
37489
  * - `helix-create`: Fired when the reader asks for something the list does not hold, and cancelable.
37490
+ * - `helix-filter`: Fired as the reader types, carrying the text the list is being narrowed to. Cancelable: refusing it leaves the list whole, and is how a consumer takes the filtering for themselves.
37135
37491
  * - `toggle`: Says the state moved, carrying `newState` and `oldState`.
37136
37492
  *
37137
37493
  * ## Slots
@@ -39344,6 +39700,190 @@ export type CustomElementsSolidJs = {
39344
39700
  BaseEvents<HelixFileInput>
39345
39701
  >;
39346
39702
 
39703
+ /**
39704
+ * The frame is the field rather than the input, so the tokens sit inside the
39705
+ * same box as the text and the focus ring is drawn once around the whole
39706
+ * control. It grows down a line at a time as tokens are added, which is the
39707
+ * arrangement Combobox takes when it is holding a selection.
39708
+ *
39709
+ * **The tokens are the consumer's own elements**, so the only thing said about
39710
+ * them here is to keep their size and not run past the field. A `Tag` slotted
39711
+ * into `tags` already looks like one; anything else looks like whatever it is.
39712
+ *
39713
+ * Height comes from the region, like every other control: `data-density` on
39714
+ * whatever holds it, not a `size` here.
39715
+ *
39716
+ * ## Attributes & Properties
39717
+ *
39718
+ * Component attributes and properties that can be applied to the element or by using JavaScript.
39719
+ *
39720
+ * - `max-tags`/`maxTags`: How many tokens to show before the rest become a count.
39721
+ * - `default-value`/`defaultValue`: The value the markup declared, which is where a reset returns to.
39722
+ * - `value`: What the control holds now, and what its form submits.
39723
+ *
39724
+ * One property, not two, so `input.value` answers the question anyone
39725
+ * asking it meant. Writing always applies; `<helix-input value="x">` is the
39726
+ * same statement in markup, and `default-value` is how markup seeds a value
39727
+ * a reset should return to.
39728
+ * - `feedback`: What is wrong, in the reader's words rather than the browser's.
39729
+ * - `hint`: Help under the control, shown while there is nothing wrong.
39730
+ * - `label`: The accessible name, and the fallback for the `label` slot.
39731
+ * - `required`: Whether the form refuses to submit without it.
39732
+ * - `clearable`: Whether the field offers a button that empties it.
39733
+ *
39734
+ * The text only. The tokens are the consumer's markup and this element is not
39735
+ * entitled to take them out of the document, which is the same reason
39736
+ * `hideOverflow` marks the ones over the cap `hidden` rather than removing
39737
+ * them.
39738
+ * - `clear-label`/`clearLabel`: What the clear button is called, since an icon has no name of its own.
39739
+ * - `placeholder`: Shown while the field is empty.
39740
+ *
39741
+ * Not a label: it goes when typing starts.
39742
+ * - `disabled`: Whether the control is non-interactive.
39743
+ *
39744
+ * Reflected, because the styled tier selects on it, and mirrored to
39745
+ * `aria-disabled` rather than removing the element from the accessibility
39746
+ * tree, so a screen reader can still announce that the control exists.
39747
+ *
39748
+ * The mirror itself is in `willUpdate` below, here rather than in each
39749
+ * control, because here is where `disabled` is.
39750
+ * - `name`: Name submitted with the form.
39751
+ *
39752
+ * **Reflected, and it is the exception to "reflect only what CSS selects
39753
+ * on".** The platform builds a form's entry list from the `name` *content
39754
+ * attribute*, not from the property, so a control named through the property
39755
+ * submitted under no name at all and was silently dropped. Measured: two
39756
+ * inputs in one form, one named by attribute and one by property, and the
39757
+ * form carried a single entry.
39758
+ *
39759
+ * Safe for a React consumer, which is what the rule is protecting: React
39760
+ * renders a custom element's props as attributes on the server, so the name
39761
+ * is already in the markup being hydrated and reflecting it writes what is
39762
+ * there. It is only a change to the markup when a consumer assigns it
39763
+ * imperatively later, and nothing is hydrating by then.
39764
+ *
39765
+ * Here rather than on each control.
39766
+ * - `form`: The form this control belongs to, if any. (property only) (readonly)
39767
+ * - `labels`: Labels associated with this control. (property only) (readonly)
39768
+ * - `whenSettled`: Resolves a frame after the first update, when transitions are switched on.
39769
+ *
39770
+ * **Named `whenSettled` because `settled` is taken four times over**, by
39771
+ * Image, Splitter and both color controls, none of them about transitions. A
39772
+ * base class takes the name every subclass then cannot use.
39773
+ *
39774
+ * **The state it reports cannot be watched, which is why this exists.** A
39775
+ * custom state is deliberately not in the DOM, so there is no
39776
+ * `MutationObserver` equivalent for `ElementInternals.states`. Await this
39777
+ * instead.
39778
+ *
39779
+ * Separate from `updateComplete`, which resolves in the microtask checkpoint
39780
+ * the suppression is still active in. That is the distinction `readyToMove`
39781
+ * in `@fusion.dev/helix-testing` is written around.
39782
+ *
39783
+ * It never resolves where `requestAnimationFrame` never fires, which is a
39784
+ * server, a hidden tab, and happy-dom. Callers that must not hang race it
39785
+ * against a timeout; `readyToMove` does exactly that. (property only) (readonly)
39786
+ *
39787
+ * ## Events
39788
+ *
39789
+ * Events that will be emitted by the component.
39790
+ *
39791
+ * - `input`: Announced once the text has moved.
39792
+ * - `change`: Relayed from the input once the reader has finished.
39793
+ * - `helix-before-change`: Fired as the text changes, and cancelable.
39794
+ *
39795
+ * ## Slots
39796
+ *
39797
+ * Areas where markup can be added to the component.
39798
+ *
39799
+ * - `end`: After the text, for a count or a control.
39800
+ * - `start`: Before the text, for a search icon.
39801
+ * - `tags`: What is already narrowing the results, as `Tag`s.
39802
+ *
39803
+ * ## Methods
39804
+ *
39805
+ * Methods that can be called to access component functionality.
39806
+ *
39807
+ * - `requestValue(next: string) => boolean`: Requests a new value, and reports whether the request stood.
39808
+ *
39809
+ * Announces before it acts, so `preventDefault()` on the `helix-before-change` is
39810
+ * a refusal and nothing moves. Nobody refusing means the control updates
39811
+ * itself, whether or not a consumer declared `value`: a declared property
39812
+ * is a seed and a correction, the way `<input value>` is, and a consumer
39813
+ * who wants the change for themselves refuses it and assigns their own.
39814
+ * - `formResetCallback() => void`: Returns the control to the value its markup declared.
39815
+ *
39816
+ * Both halves are dropped, the consumer's and the control's, because a
39817
+ * reset means the form is as it was served. Clearing only the internal one
39818
+ * would leave a control that had been written to stuck at that value.
39819
+ * - `formStateRestoreCallback(state: string | null) => void`: Restores the value when the browser brings a form back.
39820
+ *
39821
+ * Falling back to `defaultValue` rather than to empty, because a restore
39822
+ * with no state is a form the browser has nothing recorded for, which is
39823
+ * the same situation as a fresh one.
39824
+ * - `focus(options?: FocusOptions) => void`: Puts the caret in the field, the way a label pointing at one would.
39825
+ * - `formDisabledCallback(disabled: boolean) => void`: The platform's notice that an ancestor fieldset changed.
39826
+ *
39827
+ * **The argument is the effective state, and taking it whole is what latched
39828
+ * every control in the library.** The platform calls this for the element's
39829
+ * own `disabled` as well as for a fieldset, and our own arrives here at the
39830
+ * worst possible moment: reflecting `disabled` to the attribute happens
39831
+ * inside Lit's `update()`, the UA fires this synchronously from that write,
39832
+ * and a reactive write during an update is a change-in-update Lit does not
39833
+ * re-render for. So `formDisabled` ran exactly one update behind forever.
39834
+ *
39835
+ * Measured on Slider, logging what `render` saw:
39836
+ *
39837
+ * ```
39838
+ * set true disabled true formDisabled false isDisabled true
39839
+ * set false disabled false formDisabled true isDisabled true <- stale
39840
+ * (no third render)
39841
+ * ```
39842
+ *
39843
+ * The host came out right every time, `disabled` false, `:disabled` not
39844
+ * matching, and the inner control kept the attribute, so a control disabled
39845
+ * once could never be re-enabled. It only shows when something re-enables,
39846
+ * which is the same shape of bug `inheritDisabled` was written for.
39847
+ *
39848
+ * Our own half is already in `this.disabled` and `isDisabled` is an or, so
39849
+ * this records only what the fieldset adds. That also removes the write
39850
+ * entirely on the own-disabled path rather than moving it.
39851
+ *
39852
+ * The one case this cannot see is a control that is disabled itself *and*
39853
+ * inside a disabled fieldset, whose own `disabled` is then removed: the
39854
+ * effective state does not change, so the platform does not call again, and
39855
+ * the fieldset's hold is not recorded. There is no callback to learn it from
39856
+ * and reading `:disabled` here would answer about the attribute we are in the
39857
+ * middle of removing.
39858
+ *
39859
+ * ## CSS Custom Properties
39860
+ *
39861
+ * CSS variables available for styling the component.
39862
+ *
39863
+ * - `--filter-input-background-color`: Fill behind the field. (default: `undefined`)
39864
+ * - `--filter-input-control-size`: Smallest the text keeps as tokens fill the line, before it wraps to its own. (default: `undefined`)
39865
+ * - `--filter-input-size`: Height of the field with nothing in it, which it grows from. (default: `undefined`)
39866
+ *
39867
+ * ## CSS Parts
39868
+ *
39869
+ * Custom selectors for styling elements within the component.
39870
+ *
39871
+ * - `clear`: The button that empties the field.
39872
+ * - `control`: The input itself.
39873
+ * - `feedback`: What is wrong with it.
39874
+ * - `field`: The box holding everything.
39875
+ * - `hint`: Help under the field, while nothing is wrong.
39876
+ * - `label`: The question, over the field.
39877
+ * - `rest`: How many tokens did not fit.
39878
+ * - `tags`: The row the tokens sit in.
39879
+ */
39880
+ "helix-filter-input": Partial<
39881
+ HelixFilterInputProps &
39882
+ HelixFilterInputSolidJsProps &
39883
+ BaseProps<HelixFilterInput> &
39884
+ BaseEvents<HelixFilterInput>
39885
+ >;
39886
+
39347
39887
  /**
39348
39888
  * The host is the flex container itself and the only child is a slot, so the
39349
39889
  * element adds no box of its own: `<helix-flex>` costs exactly the `<div>` it
@@ -50115,6 +50655,12 @@ export type CustomCssProperties = {
50115
50655
  "--file-input-background-color"?: (string) | undefined;
50116
50656
  /** Padding inside the field. */
50117
50657
  "--file-input-padding"?: (string) | undefined;
50658
+ /** Fill behind the field. */
50659
+ "--filter-input-background-color"?: (string) | undefined;
50660
+ /** Smallest the text keeps as tokens fill the line, before it wraps to its own. */
50661
+ "--filter-input-control-size"?: (string) | undefined;
50662
+ /** Height of the field with nothing in it, which it grows from. */
50663
+ "--filter-input-size"?: (string) | undefined;
50118
50664
  /** An explicit track list, which wins over `min` and `columns`. For a layout of unequal tracks, which neither attribute can say. */
50119
50665
  "--grid-columns"?: (string) | undefined;
50120
50666
  /** How tall a cell is. A row of a tall thin cell is what a status page draws. */
package/types/svelte.d.ts CHANGED
@@ -47,6 +47,7 @@ declare module 'svelte/elements' {
47
47
  'helix-drilldown': CustomElements['helix-drilldown']
48
48
  'helix-empty': CustomElements['helix-empty']
49
49
  'helix-file-input': CustomElements['helix-file-input']
50
+ 'helix-filter-input': CustomElements['helix-filter-input']
50
51
  'helix-flex': CustomElements['helix-flex']
51
52
  'helix-format-date': CustomElements['helix-format-date']
52
53
  'helix-grid': CustomElements['helix-grid']