@deepfuture/dui-components 0.0.15 → 0.0.16

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": "@deepfuture/dui-components",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "DUI unstyled web components — structural CSS only, themed via applyTheme()",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -158,6 +158,10 @@
158
158
  "import": "./number-field/index.js",
159
159
  "types": "./number-field/index.d.ts"
160
160
  },
161
+ "./stepper": {
162
+ "import": "./stepper/index.js",
163
+ "types": "./stepper/index.d.ts"
164
+ },
161
165
  "./menubar": {
162
166
  "import": "./menubar/index.js",
163
167
  "types": "./menubar/index.d.ts"
@@ -166,6 +170,10 @@
166
170
  "import": "./calendar/index.js",
167
171
  "types": "./calendar/index.d.ts"
168
172
  },
173
+ "./split-button": {
174
+ "import": "./split-button/index.js",
175
+ "types": "./split-button/index.d.ts"
176
+ },
169
177
  "./all": {
170
178
  "import": "./all.js",
171
179
  "types": "./all.d.ts"
@@ -178,7 +186,7 @@
178
186
  "README.md"
179
187
  ],
180
188
  "dependencies": {
181
- "@deepfuture/dui-core": "0.0.15",
189
+ "@deepfuture/dui-core": "0.0.16",
182
190
  "lit": "^3.3.2",
183
191
  "@lit/context": "^1.1.3"
184
192
  },
@@ -9,5 +9,6 @@ export declare class DuiPopoverTrigger extends LitElement {
9
9
  #private;
10
10
  static tagName: "dui-popover-trigger";
11
11
  static styles: import("lit").CSSResult[];
12
+ protected updated(): void;
12
13
  render(): TemplateResult;
13
14
  }
@@ -35,6 +35,23 @@ export class DuiPopoverTrigger extends LitElement {
35
35
  const el = slot?.assignedElements()?.[0] ?? this;
36
36
  this.#ctx.value?.setTriggerEl(el);
37
37
  }
38
+ /** Mirror open state onto the slotted element so its theme can style it. */
39
+ #syncOpenAttr() {
40
+ const slot = this.shadowRoot?.querySelector("slot");
41
+ const el = slot?.assignedElements()?.[0];
42
+ if (!el)
43
+ return;
44
+ const isOpen = this.#ctx.value?.open ?? false;
45
+ if (isOpen) {
46
+ el.setAttribute("data-open", "");
47
+ }
48
+ else {
49
+ el.removeAttribute("data-open");
50
+ }
51
+ }
52
+ updated() {
53
+ this.#syncOpenAttr();
54
+ }
38
55
  render() {
39
56
  const isOpen = this.#ctx.value?.open ?? false;
40
57
  const popupId = this.#ctx.value?.popupId ?? "";
package/select/select.js CHANGED
@@ -115,6 +115,9 @@ const portalPopupStyles = [
115
115
 
116
116
  .ItemText {
117
117
  flex: 1;
118
+ white-space: nowrap;
119
+ overflow: hidden;
120
+ text-overflow: ellipsis;
118
121
  }
119
122
  `,
120
123
  ];
@@ -201,6 +204,8 @@ let DuiSelect = (() => {
201
204
  #listboxId = `select-listbox-${crypto.randomUUID().slice(0, 8)}`;
202
205
  #popup = new FloatingPortalController(this, {
203
206
  getAnchor: () => this.shadowRoot?.querySelector(".Trigger"),
207
+ matchWidth: false,
208
+ minMatchWidth: true,
204
209
  styles: portalPopupStyles,
205
210
  onOpen: () => {
206
211
  this.#highlightedIndex = this.#selectedIndex;
@@ -14,7 +14,8 @@ export declare const valueCommittedEvent: (detail: {
14
14
  * A slider for selecting numeric values within a range.
15
15
  *
16
16
  * Supports pointer drag, keyboard navigation (arrows, Page Up/Down, Home/End),
17
- * and a hidden native range input for accessibility.
17
+ * a hidden native range input for accessibility, and an optional click-to-type
18
+ * value readout (enabled via the `field` variant).
18
19
  */
19
20
  export declare class DuiSlider extends LitElement {
20
21
  #private;
@@ -32,6 +33,12 @@ export declare class DuiSlider extends LitElement {
32
33
  accessor disabled: boolean;
33
34
  /** Name for form submission. */
34
35
  accessor name: string;
36
+ /** Label text displayed by the slider. */
37
+ accessor label: string;
38
+ /** Unit suffix on the value readout (e.g. `m`, `°`, `%`). */
39
+ accessor unit: string;
40
+ /** Decimal places for value readout. Auto-inferred from `step` if not set. */
41
+ accessor precision: number | undefined;
35
42
  disconnectedCallback(): void;
36
43
  render(): TemplateResult;
37
44
  }
package/slider/slider.js CHANGED
@@ -51,7 +51,7 @@ const styles = css `
51
51
  [part="root"] {
52
52
  position: relative;
53
53
  display: flex;
54
- align-items: center;
54
+ flex-direction: column;
55
55
  width: 100%;
56
56
  touch-action: none;
57
57
  user-select: none;
@@ -61,6 +61,19 @@ const styles = css `
61
61
  pointer-events: none;
62
62
  }
63
63
 
64
+ [part="label"] {
65
+ display: flex;
66
+ align-items: center;
67
+ flex-shrink: 0;
68
+ }
69
+
70
+ .slider-row {
71
+ position: relative;
72
+ display: flex;
73
+ align-items: center;
74
+ width: 100%;
75
+ }
76
+
64
77
  [part="track"] {
65
78
  position: relative;
66
79
  flex-grow: 1;
@@ -75,6 +88,28 @@ const styles = css `
75
88
  width: var(--slider-progress, 0%);
76
89
  }
77
90
 
91
+ [part="readout"] {
92
+ position: absolute;
93
+ inset: 0;
94
+ box-sizing: border-box;
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ font: inherit;
99
+ color: inherit;
100
+ pointer-events: none;
101
+ z-index: 2;
102
+ }
103
+
104
+ [part="unit"] {
105
+ position: absolute;
106
+ right: 0;
107
+ top: 50%;
108
+ transform: translateY(-50%);
109
+ pointer-events: none;
110
+ z-index: 2;
111
+ }
112
+
78
113
  [part="thumb"] {
79
114
  position: absolute;
80
115
  left: var(--slider-progress, 0%);
@@ -104,7 +139,8 @@ const styles = css `
104
139
  * A slider for selecting numeric values within a range.
105
140
  *
106
141
  * Supports pointer drag, keyboard navigation (arrows, Page Up/Down, Home/End),
107
- * and a hidden native range input for accessibility.
142
+ * a hidden native range input for accessibility, and an optional click-to-type
143
+ * value readout (enabled via the `field` variant).
108
144
  */
109
145
  let DuiSlider = (() => {
110
146
  let _classSuper = LitElement;
@@ -126,6 +162,15 @@ let DuiSlider = (() => {
126
162
  let _name_decorators;
127
163
  let _name_initializers = [];
128
164
  let _name_extraInitializers = [];
165
+ let _label_decorators;
166
+ let _label_initializers = [];
167
+ let _label_extraInitializers = [];
168
+ let _unit_decorators;
169
+ let _unit_initializers = [];
170
+ let _unit_extraInitializers = [];
171
+ let _precision_decorators;
172
+ let _precision_initializers = [];
173
+ let _precision_extraInitializers = [];
129
174
  let _private_dragging_decorators;
130
175
  let _private_dragging_initializers = [];
131
176
  let _private_dragging_extraInitializers = [];
@@ -139,6 +184,9 @@ let DuiSlider = (() => {
139
184
  _step_decorators = [property({ type: Number })];
140
185
  _disabled_decorators = [property({ type: Boolean, reflect: true })];
141
186
  _name_decorators = [property()];
187
+ _label_decorators = [property({ reflect: true })];
188
+ _unit_decorators = [property({ reflect: true })];
189
+ _precision_decorators = [property({ type: Number })];
142
190
  _private_dragging_decorators = [state()];
143
191
  __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);
144
192
  __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);
@@ -146,6 +194,9 @@ let DuiSlider = (() => {
146
194
  __esDecorate(this, null, _step_decorators, { kind: "accessor", name: "step", static: false, private: false, access: { has: obj => "step" in obj, get: obj => obj.step, set: (obj, value) => { obj.step = value; } }, metadata: _metadata }, _step_initializers, _step_extraInitializers);
147
195
  __esDecorate(this, null, _disabled_decorators, { kind: "accessor", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, get: obj => obj.disabled, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, _disabled_initializers, _disabled_extraInitializers);
148
196
  __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);
197
+ __esDecorate(this, null, _label_decorators, { kind: "accessor", name: "label", static: false, private: false, access: { has: obj => "label" in obj, get: obj => obj.label, set: (obj, value) => { obj.label = value; } }, metadata: _metadata }, _label_initializers, _label_extraInitializers);
198
+ __esDecorate(this, null, _unit_decorators, { kind: "accessor", name: "unit", static: false, private: false, access: { has: obj => "unit" in obj, get: obj => obj.unit, set: (obj, value) => { obj.unit = value; } }, metadata: _metadata }, _unit_initializers, _unit_extraInitializers);
199
+ __esDecorate(this, null, _precision_decorators, { kind: "accessor", name: "precision", static: false, private: false, access: { has: obj => "precision" in obj, get: obj => obj.precision, set: (obj, value) => { obj.precision = value; } }, metadata: _metadata }, _precision_initializers, _precision_extraInitializers);
149
200
  __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);
150
201
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
151
202
  }
@@ -175,7 +226,19 @@ let DuiSlider = (() => {
175
226
  /** Name for form submission. */
176
227
  get name() { return this.#name_accessor_storage; }
177
228
  set name(value) { this.#name_accessor_storage = value; }
178
- #dragging_accessor_storage = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _private_dragging_initializers, false));
229
+ #label_accessor_storage = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _label_initializers, ""));
230
+ /** Label text displayed by the slider. */
231
+ get label() { return this.#label_accessor_storage; }
232
+ set label(value) { this.#label_accessor_storage = value; }
233
+ #unit_accessor_storage = (__runInitializers(this, _label_extraInitializers), __runInitializers(this, _unit_initializers, ""));
234
+ /** Unit suffix on the value readout (e.g. `m`, `°`, `%`). */
235
+ get unit() { return this.#unit_accessor_storage; }
236
+ set unit(value) { this.#unit_accessor_storage = value; }
237
+ #precision_accessor_storage = (__runInitializers(this, _unit_extraInitializers), __runInitializers(this, _precision_initializers, undefined));
238
+ /** Decimal places for value readout. Auto-inferred from `step` if not set. */
239
+ get precision() { return this.#precision_accessor_storage; }
240
+ set precision(value) { this.#precision_accessor_storage = value; }
241
+ #dragging_accessor_storage = (__runInitializers(this, _precision_extraInitializers), __runInitializers(this, _private_dragging_initializers, false));
179
242
  get #dragging() { return _private_dragging_descriptor.get.call(this); }
180
243
  set #dragging(value) { return _private_dragging_descriptor.set.call(this, value); }
181
244
  get #progress() {
@@ -184,6 +247,17 @@ let DuiSlider = (() => {
184
247
  return 0;
185
248
  return ((this.value - this.min) / range) * 100;
186
249
  }
250
+ get #inferredPrecision() {
251
+ const stepStr = String(this.step);
252
+ const dotIndex = stepStr.indexOf(".");
253
+ if (dotIndex === -1)
254
+ return 0;
255
+ return stepStr.length - dotIndex - 1;
256
+ }
257
+ get #displayValue() {
258
+ const p = this.precision ?? this.#inferredPrecision;
259
+ return this.value.toFixed(p);
260
+ }
187
261
  #clampValue(value) {
188
262
  const stepped = Math.round(value / this.step) * this.step;
189
263
  return Math.max(this.min, Math.min(this.max, stepped));
@@ -294,14 +368,21 @@ let DuiSlider = (() => {
294
368
  style="--slider-progress: ${this.#progress}%"
295
369
  @pointerdown=${this.#onPointerDown}
296
370
  >
297
- <div part="track">
298
- <div part="indicator"></div>
371
+ <span part="label">${this.label}</span>
372
+
373
+ <div class="slider-row">
374
+ <div part="track">
375
+ <div part="indicator"></div>
376
+ <span part="readout">${this.#displayValue}</span>
377
+ <span part="unit">${this.unit}</span>
378
+ </div>
379
+ <div
380
+ part="thumb"
381
+ tabindex=${this.disabled ? -1 : 0}
382
+ @keydown=${this.#onKeyDown}
383
+ ></div>
299
384
  </div>
300
- <div
301
- part="thumb"
302
- tabindex=${this.disabled ? -1 : 0}
303
- @keydown=${this.#onKeyDown}
304
- ></div>
385
+
305
386
  <input
306
387
  class="native-input"
307
388
  type="range"
@@ -314,6 +395,7 @@ let DuiSlider = (() => {
314
395
  aria-valuenow=${this.value}
315
396
  aria-valuemin=${this.min}
316
397
  aria-valuemax=${this.max}
398
+ aria-label=${this.label || "Slider"}
317
399
  @input=${this.#onNativeInput}
318
400
  @change=${this.#onNativeChange}
319
401
  />
@@ -0,0 +1 @@
1
+ export { DuiSplitButton, actionEvent } from "./split-button.js";
@@ -0,0 +1 @@
1
+ export { DuiSplitButton, actionEvent } from "./split-button.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { DuiSplitButton } from "./index.js";
2
+ if (!customElements.get(DuiSplitButton.tagName)) {
3
+ customElements.define(DuiSplitButton.tagName, DuiSplitButton);
4
+ }
@@ -0,0 +1,33 @@
1
+ import { LitElement, type TemplateResult } from "lit";
2
+ /** Fired when the action (left) button is clicked. */
3
+ export declare const actionEvent: (detail: {}) => CustomEvent<{}>;
4
+ /**
5
+ * `<dui-split-button>` — A button with an attached dropdown menu trigger.
6
+ *
7
+ * The action zone (left) performs a primary action. The menu trigger (right)
8
+ * opens a dropdown of `dui-menu-item` children for secondary actions.
9
+ *
10
+ * @slot - Action button label / content.
11
+ * @slot icon - Custom icon for the dropdown trigger (defaults to chevron-down).
12
+ * @slot menu - `dui-menu-item` elements rendered inside the dropdown popup.
13
+ * @csspart root - The outer container wrapping both zones.
14
+ * @csspart action - The left action button element.
15
+ * @csspart divider - The vertical separator between action and trigger.
16
+ * @csspart trigger - The right dropdown trigger button element.
17
+ * @fires dui-action - Fired when the action button is clicked. Detail: {}
18
+ */
19
+ export declare class DuiSplitButton extends LitElement {
20
+ #private;
21
+ static tagName: "dui-split-button";
22
+ static styles: import("lit").CSSResult[];
23
+ /** Visual variant — mapped to theme styles (e.g. neutral, primary, danger). */
24
+ accessor variant: string;
25
+ /** Visual appearance — mapped to theme styles (e.g. filled, outline, ghost). */
26
+ accessor appearance: string;
27
+ /** Size — mapped to theme styles (e.g. xs, sm, md, lg). */
28
+ accessor size: string;
29
+ /** Whether the entire split button is disabled. */
30
+ accessor disabled: boolean;
31
+ protected updated(): void;
32
+ render(): TemplateResult;
33
+ }