@deepfuture/dui-components 0.0.19 → 0.0.20

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 (46) hide show
  1. package/all.d.ts +6 -2
  2. package/all.js +12 -4
  3. package/card/card.d.ts +29 -0
  4. package/card/card.js +179 -0
  5. package/card/index.d.ts +3 -0
  6. package/card/index.js +3 -0
  7. package/checkbox/checkbox.d.ts +3 -2
  8. package/checkbox/checkbox.js +21 -46
  9. package/combobox/combobox.d.ts +3 -0
  10. package/combobox/combobox.js +21 -10
  11. package/data-table/data-table.js +4 -4
  12. package/dropzone/dropzone.js +1 -0
  13. package/field/field.d.ts +32 -0
  14. package/field/field.js +363 -0
  15. package/field/index.d.ts +1 -2
  16. package/field/index.js +1 -1
  17. package/fieldset/fieldset.d.ts +20 -0
  18. package/fieldset/fieldset.js +116 -0
  19. package/fieldset/index.d.ts +1 -0
  20. package/fieldset/index.js +1 -0
  21. package/global.d.ts +0 -2
  22. package/input/input.d.ts +4 -2
  23. package/input/input.js +27 -52
  24. package/menu/menu.d.ts +2 -0
  25. package/menu/menu.js +13 -3
  26. package/number-field/number-field.d.ts +2 -2
  27. package/number-field/number-field.js +13 -49
  28. package/package.json +10 -6
  29. package/radio/radio.d.ts +3 -2
  30. package/radio/radio.js +22 -44
  31. package/select/select.d.ts +3 -2
  32. package/select/select.js +15 -33
  33. package/slider/slider.d.ts +3 -0
  34. package/slider/slider.js +12 -5
  35. package/stepper/stepper.d.ts +0 -2
  36. package/stepper/stepper.js +7 -38
  37. package/switch/switch.d.ts +3 -2
  38. package/switch/switch.js +16 -41
  39. package/textarea/textarea.d.ts +4 -0
  40. package/textarea/textarea.js +20 -0
  41. package/field/field-context.d.ts +0 -20
  42. package/field/field-context.js +0 -2
  43. package/link/index.d.ts +0 -3
  44. package/link/index.js +0 -3
  45. package/link/link.d.ts +0 -27
  46. package/link/link.js +0 -95
package/input/input.js CHANGED
@@ -34,12 +34,10 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
34
34
  return useValue ? value : void 0;
35
35
  };
36
36
  import { css, html, LitElement } from "lit";
37
- import { property, state } from "lit/decorators.js";
38
- import { consume } from "@lit/context";
37
+ import { property } from "lit/decorators.js";
39
38
  import { ifDefined } from "lit/directives/if-defined.js";
40
39
  import { live } from "lit/directives/live.js";
41
40
  import { base } from "@deepfuture/dui-core/base";
42
- import { fieldContext } from "@deepfuture/dui-components/field";
43
41
  import { customEvent } from "@deepfuture/dui-core/event";
44
42
  export const inputChangeEvent = customEvent("input-change", {
45
43
  bubbles: true,
@@ -107,9 +105,6 @@ let DuiInput = (() => {
107
105
  let _autofocus_decorators;
108
106
  let _autofocus_initializers = [];
109
107
  let _autofocus_extraInitializers = [];
110
- let __fieldCtx_decorators;
111
- let __fieldCtx_initializers = [];
112
- let __fieldCtx_extraInitializers = [];
113
108
  return class DuiInput extends _classSuper {
114
109
  static {
115
110
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -125,7 +120,6 @@ let DuiInput = (() => {
125
120
  _name_decorators = [property({ type: String })];
126
121
  _autocomplete_decorators = [property({ type: String })];
127
122
  _autofocus_decorators = [property({ type: Boolean })];
128
- __fieldCtx_decorators = [consume({ context: fieldContext, subscribe: true }), state()];
129
123
  __esDecorate(this, null, _type_decorators, { kind: "accessor", name: "type", static: false, private: false, access: { has: obj => "type" in obj, get: obj => obj.type, set: (obj, value) => { obj.type = value; } }, metadata: _metadata }, _type_initializers, _type_extraInitializers);
130
124
  __esDecorate(this, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
131
125
  __esDecorate(this, null, _placeholder_decorators, { kind: "accessor", name: "placeholder", static: false, private: false, access: { has: obj => "placeholder" in obj, get: obj => obj.placeholder, set: (obj, value) => { obj.placeholder = value; } }, metadata: _metadata }, _placeholder_initializers, _placeholder_extraInitializers);
@@ -138,15 +132,20 @@ let DuiInput = (() => {
138
132
  __esDecorate(this, null, _name_decorators, { kind: "accessor", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
139
133
  __esDecorate(this, null, _autocomplete_decorators, { kind: "accessor", name: "autocomplete", static: false, private: false, access: { has: obj => "autocomplete" in obj, get: obj => obj.autocomplete, set: (obj, value) => { obj.autocomplete = value; } }, metadata: _metadata }, _autocomplete_initializers, _autocomplete_extraInitializers);
140
134
  __esDecorate(this, null, _autofocus_decorators, { kind: "accessor", name: "autofocus", static: false, private: false, access: { has: obj => "autofocus" in obj, get: obj => obj.autofocus, set: (obj, value) => { obj.autofocus = value; } }, metadata: _metadata }, _autofocus_initializers, _autofocus_extraInitializers);
141
- __esDecorate(this, null, __fieldCtx_decorators, { kind: "accessor", name: "_fieldCtx", static: false, private: false, access: { has: obj => "_fieldCtx" in obj, get: obj => obj._fieldCtx, set: (obj, value) => { obj._fieldCtx = value; } }, metadata: _metadata }, __fieldCtx_initializers, __fieldCtx_extraInitializers);
142
135
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
143
136
  }
144
137
  static tagName = "dui-input";
138
+ static formAssociated = true;
145
139
  static shadowRootOptions = {
146
140
  ...LitElement.shadowRootOptions,
147
141
  delegatesFocus: true,
148
142
  };
149
143
  static styles = [base, styles];
144
+ #internals;
145
+ constructor() {
146
+ super();
147
+ this.#internals = this.attachInternals();
148
+ }
150
149
  #type_accessor_storage = __runInitializers(this, _type_initializers, "text");
151
150
  /** Input type (text, email, password, etc.) */
152
151
  get type() { return this.#type_accessor_storage; }
@@ -195,55 +194,42 @@ let DuiInput = (() => {
195
194
  /** Whether the input should receive focus on mount. */
196
195
  get autofocus() { return this.#autofocus_accessor_storage; }
197
196
  set autofocus(value) { this.#autofocus_accessor_storage = value; }
198
- #_fieldCtx_accessor_storage = (__runInitializers(this, _autofocus_extraInitializers), __runInitializers(this, __fieldCtx_initializers, void 0));
199
- get _fieldCtx() { return this.#_fieldCtx_accessor_storage; }
200
- set _fieldCtx(value) { this.#_fieldCtx_accessor_storage = value; }
201
- get #controlId() {
202
- return this._fieldCtx?.controlId ?? "";
203
- }
204
- get #descriptionId() {
205
- return this._fieldCtx?.descriptionId;
206
- }
207
- get #errorId() {
208
- return this._fieldCtx?.errorId;
209
- }
210
- get #isDisabled() {
211
- return this.disabled || (this._fieldCtx?.disabled ?? false);
212
- }
213
- get #isInvalid() {
214
- return this._fieldCtx?.invalid ?? false;
215
- }
216
197
  firstUpdated() {
198
+ this.#syncValidity();
217
199
  if (this.autofocus) {
218
200
  this.focus();
219
201
  }
220
202
  }
221
- #onInput = (__runInitializers(this, __fieldCtx_extraInitializers), (event) => {
203
+ updated() {
204
+ this.#syncValidity();
205
+ }
206
+ #onInput = (__runInitializers(this, _autofocus_extraInitializers), (event) => {
222
207
  const target = event.target;
223
208
  this.value = target.value;
224
- this._fieldCtx?.markDirty();
225
- this._fieldCtx?.setFilled(this.value.length > 0);
209
+ this.#syncFormValue();
210
+ this.#syncValidity();
226
211
  this.dispatchEvent(inputChangeEvent({ value: this.value }));
227
212
  });
228
- #onFocus = () => {
229
- this._fieldCtx?.setFocused(true);
230
- };
231
- #onBlur = () => {
232
- this._fieldCtx?.setFocused(false);
233
- this._fieldCtx?.markTouched();
234
- };
213
+ willUpdate() {
214
+ this.#syncFormValue();
215
+ }
216
+ #syncFormValue() {
217
+ this.#internals.setFormValue(this.value);
218
+ }
219
+ #syncValidity() {
220
+ const input = this.shadowRoot?.querySelector("input");
221
+ if (input) {
222
+ this.#internals.setValidity(input.validity, input.validationMessage, input);
223
+ }
224
+ }
235
225
  render() {
236
- const describedBy = [this.#descriptionId, this.#isInvalid ? this.#errorId : undefined]
237
- .filter(Boolean)
238
- .join(" ") || undefined;
239
226
  return html `
240
227
  <input
241
228
  part="input"
242
- id="${this.#controlId}"
243
229
  type="${this.type}"
244
230
  .value="${live(this.value)}"
245
231
  placeholder="${this.placeholder}"
246
- ?disabled="${this.#isDisabled}"
232
+ ?disabled="${this.disabled}"
247
233
  ?required="${this.required}"
248
234
  ?readonly="${this.readonly}"
249
235
  minlength="${ifDefined(this.minLength)}"
@@ -251,18 +237,7 @@ let DuiInput = (() => {
251
237
  pattern="${ifDefined(this.pattern)}"
252
238
  name="${this.name}"
253
239
  autocomplete="${ifDefined(this.autocomplete)}"
254
- aria-describedby="${ifDefined(describedBy)}"
255
- aria-invalid="${this.#isInvalid}"
256
- ?data-disabled="${this.#isDisabled}"
257
- ?data-invalid="${this.#isInvalid}"
258
- ?data-valid="${!this.#isInvalid}"
259
- ?data-dirty="${this._fieldCtx?.dirty}"
260
- ?data-touched="${this._fieldCtx?.touched}"
261
- ?data-filled="${this._fieldCtx?.filled}"
262
- ?data-focused="${this._fieldCtx?.focused}"
263
240
  @input="${this.#onInput}"
264
- @focus="${this.#onFocus}"
265
- @blur="${this.#onBlur}"
266
241
  />
267
242
  `;
268
243
  }
package/menu/menu.d.ts CHANGED
@@ -10,6 +10,8 @@ export declare class DuiMenu extends LitElement {
10
10
  #private;
11
11
  static tagName: "dui-menu";
12
12
  static styles: import("lit").CSSResult[];
13
+ /** Sets `min-width` on the popup panel (e.g. `"200px"`). Defaults to `"var(--space-28)".` */
14
+ accessor popupMinWidth: string;
13
15
  protected updated(): void;
14
16
  render(): TemplateResult;
15
17
  }
package/menu/menu.js CHANGED
@@ -38,7 +38,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
38
38
  return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
39
39
  };
40
40
  import { css, html, LitElement } from "lit";
41
- import { state } from "lit/decorators.js";
41
+ import { property, state } from "lit/decorators.js";
42
42
  import { base } from "@deepfuture/dui-core/base";
43
43
  import { FloatingPortalController } from "@deepfuture/dui-core/floating-portal-controller";
44
44
  import { DuiMenuItem } from "./menu-item.js";
@@ -80,6 +80,9 @@ const portalPopupStyles = [
80
80
  */
81
81
  let DuiMenu = (() => {
82
82
  let _classSuper = LitElement;
83
+ let _popupMinWidth_decorators;
84
+ let _popupMinWidth_initializers = [];
85
+ let _popupMinWidth_extraInitializers = [];
83
86
  let _private_highlightedIndex_decorators;
84
87
  let _private_highlightedIndex_initializers = [];
85
88
  let _private_highlightedIndex_extraInitializers = [];
@@ -87,13 +90,19 @@ let DuiMenu = (() => {
87
90
  return class DuiMenu extends _classSuper {
88
91
  static {
89
92
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
93
+ _popupMinWidth_decorators = [property({ attribute: "popup-min-width" })];
90
94
  _private_highlightedIndex_decorators = [state()];
95
+ __esDecorate(this, null, _popupMinWidth_decorators, { kind: "accessor", name: "popupMinWidth", static: false, private: false, access: { has: obj => "popupMinWidth" in obj, get: obj => obj.popupMinWidth, set: (obj, value) => { obj.popupMinWidth = value; } }, metadata: _metadata }, _popupMinWidth_initializers, _popupMinWidth_extraInitializers);
91
96
  __esDecorate(this, _private_highlightedIndex_descriptor = { get: __setFunctionName(function () { return this.#highlightedIndex_accessor_storage; }, "#highlightedIndex", "get"), set: __setFunctionName(function (value) { this.#highlightedIndex_accessor_storage = value; }, "#highlightedIndex", "set") }, _private_highlightedIndex_decorators, { kind: "accessor", name: "#highlightedIndex", static: false, private: true, access: { has: obj => #highlightedIndex in obj, get: obj => obj.#highlightedIndex, set: (obj, value) => { obj.#highlightedIndex = value; } }, metadata: _metadata }, _private_highlightedIndex_initializers, _private_highlightedIndex_extraInitializers);
92
97
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
93
98
  }
94
99
  static tagName = "dui-menu";
95
100
  static styles = [base, hostStyles, componentStyles];
96
- #highlightedIndex_accessor_storage = __runInitializers(this, _private_highlightedIndex_initializers, -1);
101
+ #popupMinWidth_accessor_storage = __runInitializers(this, _popupMinWidth_initializers, "var(--space-28)");
102
+ /** Sets `min-width` on the popup panel (e.g. `"200px"`). Defaults to `"var(--space-28)".` */
103
+ get popupMinWidth() { return this.#popupMinWidth_accessor_storage; }
104
+ set popupMinWidth(value) { this.#popupMinWidth_accessor_storage = value; }
105
+ #highlightedIndex_accessor_storage = (__runInitializers(this, _popupMinWidth_extraInitializers), __runInitializers(this, _private_highlightedIndex_initializers, -1));
97
106
  get #highlightedIndex() { return _private_highlightedIndex_descriptor.get.call(this); }
98
107
  set #highlightedIndex(value) { return _private_highlightedIndex_descriptor.set.call(this, value); }
99
108
  #getTriggerElement = (__runInitializers(this, _private_highlightedIndex_extraInitializers), () => {
@@ -105,7 +114,7 @@ let DuiMenu = (() => {
105
114
  matchWidth: false,
106
115
  styles: portalPopupStyles,
107
116
  contentContainer: ".Menu",
108
- contentSelector: "dui-menu-item",
117
+ contentSelector: "dui-menu-item, dui-separator",
109
118
  onOpen: () => {
110
119
  this.#highlightedIndex = -1;
111
120
  this.#getTriggerElement()?.setAttribute("data-open", "");
@@ -117,6 +126,7 @@ let DuiMenu = (() => {
117
126
  renderPopup: (portal) => html `
118
127
  <div
119
128
  class="Popup"
129
+ style="${this.popupMinWidth ? `min-width:${this.popupMinWidth}` : ""}"
120
130
  ?data-starting-style="${portal.isStarting}"
121
131
  ?data-ending-style="${portal.isEnding}"
122
132
  >
@@ -1,5 +1,4 @@
1
1
  import { LitElement, type TemplateResult } from "lit";
2
- import { type FieldContext } from "@deepfuture/dui-components/field";
3
2
  export declare const valueChangeEvent: (detail: {
4
3
  value: number;
5
4
  }) => CustomEvent<{
@@ -27,8 +26,10 @@ export declare const valueCommittedEvent: (detail: {
27
26
  export declare class DuiNumberField extends LitElement {
28
27
  #private;
29
28
  static tagName: "dui-number-field";
29
+ static formAssociated: boolean;
30
30
  static shadowRootOptions: ShadowRootInit;
31
31
  static styles: import("lit").CSSResult[];
32
+ constructor();
32
33
  accessor value: number | undefined;
33
34
  accessor defaultValue: number | undefined;
34
35
  accessor min: number | undefined;
@@ -50,7 +51,6 @@ export declare class DuiNumberField extends LitElement {
50
51
  accessor clickLabel: boolean;
51
52
  accessor clickValue: boolean;
52
53
  accessor clickField: boolean;
53
- accessor _fieldCtx: FieldContext;
54
54
  connectedCallback(): void;
55
55
  willUpdate(): void;
56
56
  render(): TemplateResult;
@@ -38,11 +38,9 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
38
38
  };
39
39
  import { css, html, LitElement, nothing } from "lit";
40
40
  import { property, state } from "lit/decorators.js";
41
- import { consume } from "@lit/context";
42
41
  import { live } from "lit/directives/live.js";
43
42
  import { base } from "@deepfuture/dui-core/base";
44
43
  import { customEvent } from "@deepfuture/dui-core/event";
45
- import { fieldContext } from "@deepfuture/dui-components/field";
46
44
  export const valueChangeEvent = customEvent("value-change", { bubbles: true, composed: true });
47
45
  export const valueCommittedEvent = customEvent("value-committed", { bubbles: true, composed: true });
48
46
  /** Structural styles only — layout CSS. */
@@ -112,14 +110,6 @@ const styles = css `
112
110
  pointer-events: none;
113
111
  }
114
112
 
115
- .HiddenInput {
116
- position: absolute;
117
- pointer-events: none;
118
- opacity: 0;
119
- margin: 0;
120
- width: 0;
121
- height: 0;
122
- }
123
113
  `;
124
114
  /** Drag threshold in px before scrub starts. */
125
115
  const DRAG_THRESHOLD = 3;
@@ -218,9 +208,6 @@ let DuiNumberField = (() => {
218
208
  let _private_editing_initializers = [];
219
209
  let _private_editing_extraInitializers = [];
220
210
  let _private_editing_descriptor;
221
- let __fieldCtx_decorators;
222
- let __fieldCtx_initializers = [];
223
- let __fieldCtx_extraInitializers = [];
224
211
  return class DuiNumberField extends _classSuper {
225
212
  static {
226
213
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -249,7 +236,6 @@ let DuiNumberField = (() => {
249
236
  _private_inputText_decorators = [state()];
250
237
  _private_dragging_decorators = [state()];
251
238
  _private_editing_decorators = [state()];
252
- __fieldCtx_decorators = [consume({ context: fieldContext, subscribe: true }), state()];
253
239
  __esDecorate(this, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
254
240
  __esDecorate(this, null, _defaultValue_decorators, { kind: "accessor", name: "defaultValue", static: false, private: false, access: { has: obj => "defaultValue" in obj, get: obj => obj.defaultValue, set: (obj, value) => { obj.defaultValue = value; } }, metadata: _metadata }, _defaultValue_initializers, _defaultValue_extraInitializers);
255
241
  __esDecorate(this, null, _min_decorators, { kind: "accessor", name: "min", static: false, private: false, access: { has: obj => "min" in obj, get: obj => obj.min, set: (obj, value) => { obj.min = value; } }, metadata: _metadata }, _min_initializers, _min_extraInitializers);
@@ -275,15 +261,20 @@ let DuiNumberField = (() => {
275
261
  __esDecorate(this, _private_inputText_descriptor = { get: __setFunctionName(function () { return this.#inputText_accessor_storage; }, "#inputText", "get"), set: __setFunctionName(function (value) { this.#inputText_accessor_storage = value; }, "#inputText", "set") }, _private_inputText_decorators, { kind: "accessor", name: "#inputText", static: false, private: true, access: { has: obj => #inputText in obj, get: obj => obj.#inputText, set: (obj, value) => { obj.#inputText = value; } }, metadata: _metadata }, _private_inputText_initializers, _private_inputText_extraInitializers);
276
262
  __esDecorate(this, _private_dragging_descriptor = { get: __setFunctionName(function () { return this.#dragging_accessor_storage; }, "#dragging", "get"), set: __setFunctionName(function (value) { this.#dragging_accessor_storage = value; }, "#dragging", "set") }, _private_dragging_decorators, { kind: "accessor", name: "#dragging", static: false, private: true, access: { has: obj => #dragging in obj, get: obj => obj.#dragging, set: (obj, value) => { obj.#dragging = value; } }, metadata: _metadata }, _private_dragging_initializers, _private_dragging_extraInitializers);
277
263
  __esDecorate(this, _private_editing_descriptor = { get: __setFunctionName(function () { return this.#editing_accessor_storage; }, "#editing", "get"), set: __setFunctionName(function (value) { this.#editing_accessor_storage = value; }, "#editing", "set") }, _private_editing_decorators, { kind: "accessor", name: "#editing", static: false, private: true, access: { has: obj => #editing in obj, get: obj => obj.#editing, set: (obj, value) => { obj.#editing = value; } }, metadata: _metadata }, _private_editing_initializers, _private_editing_extraInitializers);
278
- __esDecorate(this, null, __fieldCtx_decorators, { kind: "accessor", name: "_fieldCtx", static: false, private: false, access: { has: obj => "_fieldCtx" in obj, get: obj => obj._fieldCtx, set: (obj, value) => { obj._fieldCtx = value; } }, metadata: _metadata }, __fieldCtx_initializers, __fieldCtx_extraInitializers);
279
264
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
280
265
  }
281
266
  static tagName = "dui-number-field";
267
+ static formAssociated = true;
282
268
  static shadowRootOptions = {
283
269
  ...LitElement.shadowRootOptions,
284
270
  delegatesFocus: true,
285
271
  };
286
272
  static styles = [base, styles];
273
+ #internals;
274
+ constructor() {
275
+ super();
276
+ this.#internals = this.attachInternals();
277
+ }
287
278
  #value_accessor_storage = __runInitializers(this, _value_initializers, undefined);
288
279
  // ── Core properties ────────────────────────────────────────────────
289
280
  get value() { return this.#value_accessor_storage; }
@@ -363,11 +354,8 @@ let DuiNumberField = (() => {
363
354
  #editing_accessor_storage = (__runInitializers(this, _private_dragging_extraInitializers), __runInitializers(this, _private_editing_initializers, false));
364
355
  get #editing() { return _private_editing_descriptor.get.call(this); }
365
356
  set #editing(value) { return _private_editing_descriptor.set.call(this, value); }
366
- #_fieldCtx_accessor_storage = (__runInitializers(this, _private_editing_extraInitializers), __runInitializers(this, __fieldCtx_initializers, void 0));
367
- get _fieldCtx() { return this.#_fieldCtx_accessor_storage; }
368
- set _fieldCtx(value) { this.#_fieldCtx_accessor_storage = value; }
369
357
  // ── Drag state (not reactive) ──────────────────────────────────────
370
- #dragStartX = (__runInitializers(this, __fieldCtx_extraInitializers), 0);
358
+ #dragStartX = (__runInitializers(this, _private_editing_extraInitializers), 0);
371
359
  #dragStartValue = 0;
372
360
  #dragStarted = false;
373
361
  #dragPointerId = null;
@@ -376,12 +364,6 @@ let DuiNumberField = (() => {
376
364
  get #currentValue() {
377
365
  return this.value ?? this.#internalValue;
378
366
  }
379
- get #isDisabled() {
380
- return this.disabled || (this._fieldCtx?.disabled ?? false);
381
- }
382
- get #isInvalid() {
383
- return this._fieldCtx?.invalid ?? false;
384
- }
385
367
  get #inferredPrecision() {
386
368
  const stepStr = String(this.step);
387
369
  const dotIndex = stepStr.indexOf(".");
@@ -455,6 +437,7 @@ let DuiNumberField = (() => {
455
437
  if (!this.#editing) {
456
438
  this.#syncInputText();
457
439
  }
440
+ this.#internals.setFormValue(this.#currentValue !== undefined ? String(this.#currentValue) : null);
458
441
  }
459
442
  // ── Value helpers ──────────────────────────────────────────────────
460
443
  #syncInputText() {
@@ -472,18 +455,16 @@ let DuiNumberField = (() => {
472
455
  if (this.value === undefined) {
473
456
  this.#internalValue = clamped;
474
457
  }
475
- this._fieldCtx?.markDirty();
476
- this._fieldCtx?.setFilled(true);
477
458
  this.dispatchEvent(valueChangeEvent({ value: clamped }));
478
459
  }
479
460
  #increment = (amount) => {
480
- if (this.#isDisabled || this.readOnly)
461
+ if (this.disabled || this.readOnly)
481
462
  return;
482
463
  const current = this.#currentValue ?? this.min ?? 0;
483
464
  this.#setValue(current + amount);
484
465
  };
485
466
  #decrement = (amount) => {
486
- if (this.#isDisabled || this.readOnly)
467
+ if (this.disabled || this.readOnly)
487
468
  return;
488
469
  const current = this.#currentValue ?? this.max ?? 0;
489
470
  this.#setValue(current - amount);
@@ -512,7 +493,7 @@ let DuiNumberField = (() => {
512
493
  }
513
494
  // ── Drag-to-scrub ─────────────────────────────────────────────────
514
495
  #startDrag(e, allowsClick) {
515
- if (this.#isDisabled || this.readOnly)
496
+ if (this.disabled || this.readOnly)
516
497
  return;
517
498
  this.#dragPointerId = e.pointerId;
518
499
  this.#dragStartX = e.clientX;
@@ -631,12 +612,9 @@ let DuiNumberField = (() => {
631
612
  if (this.#editing) {
632
613
  this.#commitInput();
633
614
  }
634
- this._fieldCtx?.setFocused(false);
635
- this._fieldCtx?.markTouched();
636
615
  };
637
616
  #onFocus = () => {
638
617
  this.#editing = true;
639
- this._fieldCtx?.setFocused(true);
640
618
  const input = this.shadowRoot?.querySelector('[part="input"]');
641
619
  if (input) {
642
620
  requestAnimationFrame(() => input.select());
@@ -697,9 +675,6 @@ let DuiNumberField = (() => {
697
675
  };
698
676
  // ── Render ─────────────────────────────────────────────────────────
699
677
  render() {
700
- const isDisabled = this.#isDisabled;
701
- const isInvalid = this.#isInvalid;
702
- const controlId = this._fieldCtx?.controlId ?? "";
703
678
  const currentValue = this.#currentValue;
704
679
  // Compute which zones are scrubbable for cursor styling
705
680
  const labelScrub = this.#effectiveScrubLabel || this.#effectiveScrubField;
@@ -716,9 +691,8 @@ let DuiNumberField = (() => {
716
691
  part="root"
717
692
  ?data-scrub="${rootScrub}"
718
693
  ?data-dragging="${this.#dragging}"
719
- ?data-disabled="${isDisabled}"
694
+ ?data-disabled="${this.disabled}"
720
695
  ?data-readonly="${this.readOnly}"
721
- ?data-invalid="${isInvalid}"
722
696
  @pointerdown="${this.#onRootPointerDown}"
723
697
  >
724
698
  <span part="icon">
@@ -727,20 +701,17 @@ let DuiNumberField = (() => {
727
701
 
728
702
  <input
729
703
  part="input"
730
- id="${controlId || nothing}"
731
704
  type="text"
732
705
  inputmode="decimal"
733
706
  ?data-scrub="${inputScrub}"
734
707
  .value="${live(this.#inputText)}"
735
- ?disabled="${isDisabled}"
708
+ ?disabled="${this.disabled}"
736
709
  ?readonly="${this.readOnly}"
737
710
  ?required="${this.required}"
738
711
  aria-label="${this.label || nothing}"
739
712
  aria-valuenow="${currentValue ?? nothing}"
740
713
  aria-valuemin="${this.min ?? nothing}"
741
714
  aria-valuemax="${this.max ?? nothing}"
742
- aria-invalid="${isInvalid ? "true" : nothing}"
743
- ?data-disabled="${isDisabled}"
744
715
  @pointerdown="${this.#onInputPointerDown}"
745
716
  @input="${this.#onInput}"
746
717
  @keydown="${this.#onKeyDown}"
@@ -750,13 +721,6 @@ let DuiNumberField = (() => {
750
721
 
751
722
  <span part="unit">${this.unit}</span>
752
723
 
753
- ${this.name
754
- ? html `<input
755
- type="hidden"
756
- name="${this.name}"
757
- .value="${String(currentValue ?? "")}"
758
- />`
759
- : nothing}
760
724
  </div>
761
725
  `;
762
726
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepfuture/dui-components",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "DUI unstyled web components — structural CSS only, themed via applyTheme()",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -94,10 +94,6 @@
94
94
  "import": "./trunc/index.js",
95
95
  "types": "./trunc/index.d.ts"
96
96
  },
97
- "./link": {
98
- "import": "./link/index.js",
99
- "types": "./link/index.d.ts"
100
- },
101
97
  "./avatar": {
102
98
  "import": "./avatar/index.js",
103
99
  "types": "./avatar/index.d.ts"
@@ -110,6 +106,10 @@
110
106
  "import": "./field/index.js",
111
107
  "types": "./field/index.d.ts"
112
108
  },
109
+ "./fieldset": {
110
+ "import": "./fieldset/index.js",
111
+ "types": "./fieldset/index.d.ts"
112
+ },
113
113
  "./input": {
114
114
  "import": "./input/index.js",
115
115
  "types": "./input/index.d.ts"
@@ -174,6 +174,10 @@
174
174
  "import": "./split-button/index.js",
175
175
  "types": "./split-button/index.d.ts"
176
176
  },
177
+ "./card": {
178
+ "import": "./card/index.js",
179
+ "types": "./card/index.d.ts"
180
+ },
177
181
  "./card-grid": {
178
182
  "import": "./card-grid/index.js",
179
183
  "types": "./card-grid/index.d.ts"
@@ -190,7 +194,7 @@
190
194
  "README.md"
191
195
  ],
192
196
  "dependencies": {
193
- "@deepfuture/dui-core": "0.0.19",
197
+ "@deepfuture/dui-core": "0.0.20",
194
198
  "lit": "^3.3.2",
195
199
  "@lit/context": "^1.1.3"
196
200
  },
package/radio/radio.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  /** Ported from original DUI: deep-future-app/app/client/components/dui/radio */
2
2
  import { LitElement, type TemplateResult } from "lit";
3
- import { type FieldContext } from "@deepfuture/dui-components/field";
4
3
  /**
5
4
  * `<dui-radio>` — A radio button input.
6
5
  *
@@ -15,15 +14,17 @@ import { type FieldContext } from "@deepfuture/dui-components/field";
15
14
  export declare class DuiRadio extends LitElement {
16
15
  #private;
17
16
  static tagName: "dui-radio";
17
+ static formAssociated: boolean;
18
18
  static styles: import("lit").CSSResult[];
19
+ constructor();
19
20
  /** The value attribute for this radio option. */
20
21
  accessor value: string;
21
22
  /** Whether the radio is disabled. */
22
23
  accessor disabled: boolean;
23
24
  /** Whether the radio is read-only. */
24
25
  accessor readOnly: boolean;
25
- accessor _fieldCtx: FieldContext;
26
26
  connectedCallback(): void;
27
+ willUpdate(): void;
27
28
  disconnectedCallback(): void;
28
29
  render(): TemplateResult;
29
30
  }