@filipgutica/ui 1.12.0 → 1.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.
@@ -0,0 +1,25 @@
1
+ import type { UiControlSize } from '../control.js';
2
+ export interface UiSwitchProps {
3
+ description?: string;
4
+ disabled?: boolean;
5
+ id?: string;
6
+ label?: string;
7
+ modelValue?: boolean;
8
+ size?: UiControlSize;
9
+ }
10
+ type __VLS_Slots = {
11
+ default?(): unknown;
12
+ };
13
+ declare const __VLS_base: import("vue").DefineComponent<UiSwitchProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
14
+ "update:modelValue": (value: boolean) => any;
15
+ }, string, import("vue").PublicProps, Readonly<UiSwitchProps> & Readonly<{
16
+ "onUpdate:modelValue"?: (value: boolean) => any;
17
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
19
+ declare const _default: typeof __VLS_export;
20
+ export default _default;
21
+ type __VLS_WithSlots<T, S> = T & {
22
+ new (): {
23
+ $slots: S;
24
+ };
25
+ };
package/dist/index.d.ts CHANGED
@@ -34,6 +34,8 @@ export { default as UiSlider } from './components/UiSlider.vue';
34
34
  export type { UiSliderProps } from './components/UiSlider.vue';
35
35
  export { default as UiTabs } from './components/UiTabs.vue';
36
36
  export type { UiTabItem, UiTabsProps } from './components/UiTabs.vue';
37
+ export { default as UiSwitch } from './components/UiSwitch.vue';
38
+ export type { UiSwitchProps } from './components/UiSwitch.vue';
37
39
  export { default as UiToggleButton } from './components/UiToggleButton.vue';
38
40
  export type { UiToggleButtonProps } from './components/UiToggleButton.vue';
39
41
  /** @deprecated Use UiCard for structured content. */
package/dist/index.js CHANGED
@@ -1,67 +1,67 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-DCS_wyYq.js";
2
- import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, inject as h, mergeModels as g, mergeProps as _, normalizeStyle as v, openBlock as y, provide as b, ref as ee, renderList as x, renderSlot as S, resolveDynamicComponent as C, shallowRef as te, toDisplayString as w, unref as T, useId as E, useModel as D, useSlots as O, watch as ne, withCtx as k } from "vue";
3
- import { CheckboxIndicator as re, CheckboxRoot as A, Primitive as j, ProgressIndicator as M, ProgressRoot as N, RadioGroupItem as P, RadioGroupRoot as F, SliderRange as I, SliderRoot as L, SliderThumb as R, SliderTrack as z, Toggle as B } from "reka-ui";
2
+ import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, inject as h, mergeModels as g, mergeProps as _, normalizeStyle as v, openBlock as y, provide as b, ref as ee, renderList as x, renderSlot as S, resolveDynamicComponent as C, shallowRef as te, toDisplayString as w, unref as T, useAttrs as E, useId as D, useModel as O, useSlots as k, watch as ne, withCtx as A } from "vue";
3
+ import { CheckboxIndicator as re, CheckboxRoot as j, Primitive as M, ProgressIndicator as N, ProgressRoot as P, RadioGroupItem as F, RadioGroupRoot as I, SliderRange as L, SliderRoot as R, SliderThumb as z, SliderTrack as B, Toggle as V } from "reka-ui";
4
4
  //#region src/components/UiCard.vue?vue&type=script&setup=true&lang.ts
5
- var V = { class: "fg-card" }, H = {
5
+ var H = { class: "fg-card" }, U = {
6
6
  key: 0,
7
7
  class: "fg-card__header"
8
- }, U = {
8
+ }, W = {
9
9
  key: 1,
10
10
  class: "fg-card__actions"
11
- }, W = {
11
+ }, G = {
12
12
  key: 1,
13
13
  class: "fg-card__body"
14
- }, G = {
14
+ }, K = {
15
15
  key: 2,
16
16
  class: "fg-card__footer"
17
- }, K = /* @__PURE__ */ m({
17
+ }, q = /* @__PURE__ */ m({
18
18
  __name: "UiCard",
19
19
  props: {
20
20
  title: { default: () => void 0 },
21
21
  titleTag: { default: "h3" }
22
22
  },
23
23
  setup(e) {
24
- let t = O();
25
- return (n, r) => (y(), u("div", V, [
26
- e.title || t.title || t.actions ? (y(), u("header", H, [e.title || t.title ? (y(), c(C(e.titleTag), {
24
+ let t = k();
25
+ return (n, r) => (y(), u("div", H, [
26
+ e.title || t.title || t.actions ? (y(), u("header", U, [e.title || t.title ? (y(), c(C(e.titleTag), {
27
27
  key: 0,
28
28
  class: "fg-card__title"
29
29
  }, {
30
- default: k(() => [S(n.$slots, "title", {}, () => [f(w(e.title), 1)])]),
30
+ default: A(() => [S(n.$slots, "title", {}, () => [f(w(e.title), 1)])]),
31
31
  _: 3
32
- })) : l("", !0), t.actions ? (y(), u("div", U, [S(n.$slots, "actions")])) : l("", !0)])) : l("", !0),
33
- t.default ? (y(), u("div", W, [S(n.$slots, "default")])) : l("", !0),
34
- t.footer ? (y(), u("footer", G, [S(n.$slots, "footer")])) : l("", !0)
32
+ })) : l("", !0), t.actions ? (y(), u("div", W, [S(n.$slots, "actions")])) : l("", !0)])) : l("", !0),
33
+ t.default ? (y(), u("div", G, [S(n.$slots, "default")])) : l("", !0),
34
+ t.footer ? (y(), u("footer", K, [S(n.$slots, "footer")])) : l("", !0)
35
35
  ]));
36
36
  }
37
- }), q = [
37
+ }), J = [
38
38
  "data-command",
39
39
  "data-wrap",
40
40
  "data-line-numbers",
41
41
  "data-variant"
42
- ], J = {
42
+ ], Y = {
43
43
  key: 0,
44
44
  class: "fg-code-block__header"
45
- }, Y = {
45
+ }, X = {
46
46
  key: 0,
47
47
  class: "fg-code-block__title"
48
- }, X = {
48
+ }, ie = {
49
49
  key: 1,
50
50
  class: "fg-code-block__language"
51
- }, ie = { class: "fg-code-block__actions" }, ae = ["disabled", "title"], oe = {
51
+ }, ae = { class: "fg-code-block__actions" }, oe = ["disabled", "title"], se = {
52
52
  viewBox: "0 0 24 24",
53
53
  fill: "none",
54
54
  stroke: "currentColor",
55
55
  "stroke-width": "1.5",
56
56
  "aria-hidden": "true"
57
- }, se = {
57
+ }, ce = {
58
58
  key: 0,
59
59
  d: "m5 12 4 4L19 6"
60
- }, ce = { key: 0 }, le = ["aria-label"], ue = {
60
+ }, le = { key: 0 }, ue = ["aria-label"], de = {
61
61
  key: 0,
62
62
  class: "fg-code-block__number",
63
63
  "aria-hidden": "true"
64
- }, de = { class: "fg-code-block__text" }, fe = ["data-state"], pe = /* @__PURE__ */ m({
64
+ }, fe = { class: "fg-code-block__text" }, pe = ["data-state"], me = /* @__PURE__ */ m({
65
65
  __name: "UiCodeBlock",
66
66
  props: {
67
67
  code: {},
@@ -136,10 +136,10 @@ var V = { class: "fg-card" }, H = {
136
136
  "data-line-numbers": t.lineNumbers,
137
137
  "data-variant": t.variant
138
138
  }, [
139
- t.variant === "default" || t.copyable || e.$slots.actions ? (y(), u("div", J, [
140
- t.variant === "default" ? (y(), u("span", Y, w(t.title || t.language), 1)) : l("", !0),
141
- t.title && t.variant === "default" ? (y(), u("span", X, w(t.language), 1)) : l("", !0),
142
- d("div", ie, [S(e.$slots, "actions"), t.copyable ? (y(), u("button", {
139
+ t.variant === "default" || t.copyable || e.$slots.actions ? (y(), u("div", Y, [
140
+ t.variant === "default" ? (y(), u("span", X, w(t.title || t.language), 1)) : l("", !0),
141
+ t.title && t.variant === "default" ? (y(), u("span", ie, w(t.language), 1)) : l("", !0),
142
+ d("div", ae, [S(e.$slots, "actions"), t.copyable ? (y(), u("button", {
143
143
  key: 0,
144
144
  type: "button",
145
145
  class: "fg-code-block__copy",
@@ -147,13 +147,13 @@ var V = { class: "fg-card" }, H = {
147
147
  "aria-label": "Copy code",
148
148
  title: t.variant === "compact" ? _.value ? "Copied" : "Copy code" : void 0,
149
149
  onClick: E
150
- }, [(y(), u("svg", oe, [t.variant === "compact" && _.value ? (y(), u("path", se)) : (y(), u(o, { key: 1 }, [r[0] ||= d("rect", {
150
+ }, [(y(), u("svg", se, [t.variant === "compact" && _.value ? (y(), u("path", ce)) : (y(), u(o, { key: 1 }, [r[0] ||= d("rect", {
151
151
  x: "8",
152
152
  y: "8",
153
153
  width: "12",
154
154
  height: "13",
155
155
  rx: "2"
156
- }, null, -1), r[1] ||= d("path", { d: "M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3" }, null, -1)], 64))])), t.variant === "default" ? (y(), u("span", ce, w(_.value ? "Copied" : "Copy"), 1)) : l("", !0)], 8, ae)) : l("", !0)])
156
+ }, null, -1), r[1] ||= d("path", { d: "M16 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3" }, null, -1)], 64))])), t.variant === "default" ? (y(), u("span", le, w(_.value ? "Copied" : "Copy"), 1)) : l("", !0)], 8, oe)) : l("", !0)])
157
157
  ])) : l("", !0),
158
158
  d("pre", {
159
159
  class: "fg-code-block__pre",
@@ -162,45 +162,45 @@ var V = { class: "fg-card" }, H = {
162
162
  }, [d("code", null, [(y(!0), u(o, null, x(a.value, (e, n) => (y(), u("span", {
163
163
  key: n,
164
164
  class: "fg-code-block__line"
165
- }, [t.lineNumbers ? (y(), u("span", ue, w(n + 1), 1)) : l("", !0), d("span", de, [(y(!0), u(o, null, x(e, (e, t) => (y(), u("span", {
165
+ }, [t.lineNumbers ? (y(), u("span", de, w(n + 1), 1)) : l("", !0), d("span", fe, [(y(!0), u(o, null, x(e, (e, t) => (y(), u("span", {
166
166
  key: t,
167
167
  style: v({ color: e.color })
168
- }, w(e.content), 5))), 128)), f(w(n < a.value.length - 1 ? "\n" : ""), 1)])]))), 128))])], 8, le),
168
+ }, w(e.content), 5))), 128)), f(w(n < a.value.length - 1 ? "\n" : ""), 1)])]))), 128))])], 8, ue),
169
169
  d("span", {
170
170
  class: "fg-code-block__status",
171
171
  role: "status",
172
172
  "data-state": b.value ? "success" : void 0
173
- }, w(C.value), 9, fe)
174
- ], 8, q));
173
+ }, w(C.value), 9, pe)
174
+ ], 8, J));
175
175
  }
176
- }), me = /* @__PURE__ */ m({
176
+ }), he = /* @__PURE__ */ m({
177
177
  __name: "UiAlert",
178
178
  props: { tone: { default: "neutral" } },
179
179
  setup(e) {
180
- return (t, n) => (y(), c(T(j), {
180
+ return (t, n) => (y(), c(T(M), {
181
181
  as: "div",
182
182
  class: "fg-alert",
183
183
  "data-tone": e.tone,
184
184
  role: e.tone === "danger" || e.tone === "error" ? "alert" : "status"
185
185
  }, {
186
- default: k(() => [S(t.$slots, "default")]),
186
+ default: A(() => [S(t.$slots, "default")]),
187
187
  _: 3
188
188
  }, 8, ["data-tone", "role"]));
189
189
  }
190
- }), he = /* @__PURE__ */ m({
190
+ }), ge = /* @__PURE__ */ m({
191
191
  __name: "UiBadge",
192
192
  props: { tone: { default: "neutral" } },
193
193
  setup(e) {
194
- return (t, n) => (y(), c(T(j), {
194
+ return (t, n) => (y(), c(T(M), {
195
195
  as: "span",
196
196
  class: "fg-badge",
197
197
  "data-tone": e.tone
198
198
  }, {
199
- default: k(() => [S(t.$slots, "default")]),
199
+ default: A(() => [S(t.$slots, "default")]),
200
200
  _: 3
201
201
  }, 8, ["data-tone"]));
202
202
  }
203
- }), ge = ["data-size", "data-disabled"], _e = { class: "fg-checkbox__label" }, ve = /* @__PURE__ */ m({
203
+ }), _e = ["data-size", "data-disabled"], ve = { class: "fg-checkbox__label" }, ye = /* @__PURE__ */ m({
204
204
  __name: "UiCheckbox",
205
205
  props: {
206
206
  disabled: {
@@ -222,20 +222,20 @@ var V = { class: "fg-card" }, H = {
222
222
  class: "fg-checkbox",
223
223
  "data-size": e.size,
224
224
  "data-disabled": e.disabled ? "true" : void 0
225
- }, [p(T(A), {
225
+ }, [p(T(j), {
226
226
  class: "fg-checkbox__control",
227
227
  disabled: e.disabled,
228
228
  "model-value": e.modelValue,
229
229
  "onUpdate:modelValue": r
230
230
  }, {
231
- default: k(() => [p(T(re), { class: "fg-checkbox__indicator" }, {
232
- default: k(() => [...n[0] ||= [f("✓", -1)]]),
231
+ default: A(() => [p(T(re), { class: "fg-checkbox__indicator" }, {
232
+ default: A(() => [...n[0] ||= [f("✓", -1)]]),
233
233
  _: 1
234
234
  })]),
235
235
  _: 1
236
- }, 8, ["disabled", "model-value"]), d("span", _e, [S(t.$slots, "default")])], 8, ge));
236
+ }, 8, ["disabled", "model-value"]), d("span", ve, [S(t.$slots, "default")])], 8, _e));
237
237
  }
238
- }), Z = Symbol("UiFieldContext"), ye = ["data-invalid"], be = ["for"], xe = ["id"], Se = ["id"], Ce = /* @__PURE__ */ m({
238
+ }), Z = Symbol("UiFieldContext"), be = ["data-invalid"], xe = ["for"], Se = ["id"], Ce = ["id"], we = /* @__PURE__ */ m({
239
239
  __name: "UiField",
240
240
  props: {
241
241
  controlId: {},
@@ -257,7 +257,7 @@ var V = { class: "fg-card" }, H = {
257
257
  d("label", {
258
258
  class: "fg-field__label",
259
259
  for: e.controlId
260
- }, w(e.label), 9, be),
260
+ }, w(e.label), 9, xe),
261
261
  S(r.$slots, "default", {
262
262
  descriptionId: t.value,
263
263
  errorId: n.value
@@ -267,40 +267,40 @@ var V = { class: "fg-card" }, H = {
267
267
  id: t.value,
268
268
  class: "fg-field__description",
269
269
  "data-field-description": ""
270
- }, w(e.description), 9, xe)) : l("", !0),
270
+ }, w(e.description), 9, Se)) : l("", !0),
271
271
  e.error ? (y(), u("p", {
272
272
  key: 1,
273
273
  id: n.value,
274
274
  class: "fg-field__error",
275
275
  "data-field-error": ""
276
- }, w(e.error), 9, Se)) : l("", !0)
277
- ], 8, ye));
276
+ }, w(e.error), 9, Ce)) : l("", !0)
277
+ ], 8, be));
278
278
  }
279
- }), we = { class: "fg-figure" }, Te = ["aria-labelledby", "aria-label"], Ee = ["id"], De = {
279
+ }), Te = { class: "fg-figure" }, Ee = ["aria-labelledby", "aria-label"], De = ["id"], Oe = {
280
280
  key: 0,
281
281
  class: "fg-figure__number"
282
- }, Oe = /* @__PURE__ */ m({
282
+ }, ke = /* @__PURE__ */ m({
283
283
  __name: "UiFigure",
284
284
  props: { number: { default: () => void 0 } },
285
285
  setup(e) {
286
- let t = O(), n = E(), r = () => e.number !== void 0 || !!t.caption;
287
- return (t, i) => (y(), u("figure", we, [d("div", {
286
+ let t = k(), n = D(), r = () => e.number !== void 0 || !!t.caption;
287
+ return (t, i) => (y(), u("figure", Te, [d("div", {
288
288
  class: "fg-figure__plate",
289
289
  role: "region",
290
290
  tabindex: "0",
291
291
  "aria-labelledby": r() ? T(n) : void 0,
292
292
  "aria-label": r() ? void 0 : "Figure"
293
- }, [S(t.$slots, "default")], 8, Te), r() ? (y(), u("figcaption", {
293
+ }, [S(t.$slots, "default")], 8, Ee), r() ? (y(), u("figcaption", {
294
294
  key: 0,
295
295
  id: T(n),
296
296
  class: "fg-figure__caption"
297
297
  }, [
298
- e.number === void 0 ? l("", !0) : (y(), u("span", De, "Figure " + w(e.number) + ".", 1)),
298
+ e.number === void 0 ? l("", !0) : (y(), u("span", Oe, "Figure " + w(e.number) + ".", 1)),
299
299
  i[0] ||= f(),
300
300
  S(t.$slots, "caption")
301
- ], 8, Ee)) : l("", !0)]));
301
+ ], 8, De)) : l("", !0)]));
302
302
  }
303
- }), ke = /* @__PURE__ */ m({
303
+ }), Ae = /* @__PURE__ */ m({
304
304
  __name: "UiInput",
305
305
  props: {
306
306
  disabled: {
@@ -321,7 +321,7 @@ var V = { class: "fg-card" }, H = {
321
321
  let n = h(Z, void 0), r = t, i = (e) => {
322
322
  e.currentTarget instanceof HTMLInputElement && r("update:modelValue", e.currentTarget.value);
323
323
  };
324
- return (t, r) => (y(), c(T(j), {
324
+ return (t, r) => (y(), c(T(M), {
325
325
  id: T(n)?.controlId.value ?? e.id,
326
326
  as: "input",
327
327
  class: "fg-input",
@@ -344,7 +344,7 @@ var V = { class: "fg-card" }, H = {
344
344
  "value"
345
345
  ]));
346
346
  }
347
- }), Ae = 100, je = /* @__PURE__ */ m({
347
+ }), je = 100, Me = /* @__PURE__ */ m({
348
348
  __name: "UiProgress",
349
349
  props: {
350
350
  label: {},
@@ -353,19 +353,19 @@ var V = { class: "fg-card" }, H = {
353
353
  },
354
354
  setup(e) {
355
355
  let t = s(() => {
356
- let t = Number.isFinite(e.max) && e.max > 0 ? e.max : Ae;
356
+ let t = Number.isFinite(e.max) && e.max > 0 ? e.max : je;
357
357
  return {
358
358
  max: t,
359
359
  value: e.value === null || !Number.isFinite(e.value) ? null : Math.min(t, Math.max(0, e.value))
360
360
  };
361
361
  }), n = s(() => t.value.value === null ? 0 : t.value.value / t.value.max * 100);
362
- return (r, i) => (y(), c(T(N), {
362
+ return (r, i) => (y(), c(T(P), {
363
363
  class: "fg-progress",
364
364
  "aria-label": e.label,
365
365
  max: t.value.max,
366
366
  "model-value": t.value.value
367
367
  }, {
368
- default: k(() => [p(T(M), {
368
+ default: A(() => [p(T(N), {
369
369
  class: "fg-progress__indicator",
370
370
  style: v({ transform: `translateX(-${100 - n.value}%)` })
371
371
  }, null, 8, ["style"])]),
@@ -376,7 +376,7 @@ var V = { class: "fg-card" }, H = {
376
376
  "model-value"
377
377
  ]));
378
378
  }
379
- }), Me = { class: "fg-radio-card__content" }, Ne = /* @__PURE__ */ m({
379
+ }), Ne = { class: "fg-radio-card__content" }, Pe = /* @__PURE__ */ m({
380
380
  __name: "UiRadioCard",
381
381
  props: {
382
382
  disabled: {
@@ -386,19 +386,19 @@ var V = { class: "fg-card" }, H = {
386
386
  value: {}
387
387
  },
388
388
  setup(e) {
389
- return (t, n) => (y(), c(T(P), {
389
+ return (t, n) => (y(), c(T(F), {
390
390
  class: "fg-radio-card",
391
391
  disabled: e.disabled,
392
392
  value: e.value
393
393
  }, {
394
- default: k(() => [n[0] ||= d("span", {
394
+ default: A(() => [n[0] ||= d("span", {
395
395
  class: "fg-radio-card__indicator",
396
396
  "aria-hidden": "true"
397
- }, null, -1), d("span", Me, [S(t.$slots, "default")])]),
397
+ }, null, -1), d("span", Ne, [S(t.$slots, "default")])]),
398
398
  _: 3
399
399
  }, 8, ["disabled", "value"]));
400
400
  }
401
- }), Pe = /* @__PURE__ */ m({
401
+ }), Fe = /* @__PURE__ */ m({
402
402
  __name: "UiRadioCardGroup",
403
403
  props: /*@__PURE__*/ g({
404
404
  disabled: {
@@ -416,7 +416,7 @@ var V = { class: "fg-card" }, H = {
416
416
  }),
417
417
  emits: ["update:modelValue"],
418
418
  setup(e) {
419
- let t = D(e, "modelValue"), n = (t) => {
419
+ let t = O(e, "modelValue"), n = (t) => {
420
420
  if (t.altKey || t.ctrlKey || t.metaKey || t.shiftKey) return;
421
421
  let n = t.currentTarget, r = t.target;
422
422
  if (!(n instanceof HTMLElement) || !(r instanceof HTMLElement)) return;
@@ -432,14 +432,14 @@ var V = { class: "fg-card" }, H = {
432
432
  let d = o[u];
433
433
  !d || d === r || (t.preventDefault(), d.focus(), d.click());
434
434
  };
435
- return (r, i) => (y(), c(T(F), _({
435
+ return (r, i) => (y(), c(T(I), _({
436
436
  modelValue: t.value,
437
437
  "onUpdate:modelValue": i[0] ||= (e) => t.value = e,
438
438
  class: "fg-radio-card-group",
439
439
  disabled: e.disabled,
440
440
  loop: e.loop
441
441
  }, e.orientation === void 0 ? {} : { orientation: e.orientation }, { onKeydown: n }), {
442
- default: k(() => [S(r.$slots, "default")]),
442
+ default: A(() => [S(r.$slots, "default")]),
443
443
  _: 3
444
444
  }, 16, [
445
445
  "modelValue",
@@ -447,30 +447,30 @@ var V = { class: "fg-card" }, H = {
447
447
  "loop"
448
448
  ]));
449
449
  }
450
- }), Fe = { class: "fg-score" }, Q = {
450
+ }), Ie = { class: "fg-score" }, Le = {
451
451
  class: "fg-score__pips",
452
452
  "aria-hidden": "true"
453
- }, Ie = ["data-filled"], Le = { class: "fg-score__value" }, Re = { class: "fg-score__max" }, $ = 3, ze = /* @__PURE__ */ m({
453
+ }, Re = ["data-filled"], ze = { class: "fg-score__value" }, Be = { class: "fg-score__max" }, Q = 3, Ve = /* @__PURE__ */ m({
454
454
  __name: "UiScore",
455
455
  props: {
456
- max: { default: () => $ },
456
+ max: { default: () => Q },
457
457
  score: {}
458
458
  },
459
459
  setup(e) {
460
460
  let t = s(() => {
461
- let t = Number.isInteger(e.max) && e.max > 0 ? e.max : $;
461
+ let t = Number.isInteger(e.max) && e.max > 0 ? e.max : Q;
462
462
  return {
463
463
  max: t,
464
464
  score: Number.isFinite(e.score) ? Math.min(t, Math.max(0, e.score)) : 0
465
465
  };
466
466
  });
467
- return (e, n) => (y(), u("span", Fe, [d("span", Q, [(y(!0), u(o, null, x(t.value.max, (e) => (y(), u("span", {
467
+ return (e, n) => (y(), u("span", Ie, [d("span", Le, [(y(!0), u(o, null, x(t.value.max, (e) => (y(), u("span", {
468
468
  key: e,
469
469
  class: "fg-score__pip",
470
470
  "data-filled": e <= t.value.score ? "true" : void 0
471
- }, null, 8, Ie))), 128))]), d("span", Le, [f(w(t.value.score), 1), d("span", Re, "/" + w(t.value.max), 1)])]));
471
+ }, null, 8, Re))), 128))]), d("span", ze, [f(w(t.value.score), 1), d("span", Be, "/" + w(t.value.max), 1)])]));
472
472
  }
473
- }), Be = /* @__PURE__ */ m({
473
+ }), $ = /* @__PURE__ */ m({
474
474
  __name: "UiSelect",
475
475
  props: {
476
476
  disabled: {
@@ -490,7 +490,7 @@ var V = { class: "fg-card" }, H = {
490
490
  let n = h(Z, void 0), r = t, i = (e) => {
491
491
  e.currentTarget instanceof HTMLSelectElement && r("update:modelValue", e.currentTarget.value);
492
492
  };
493
- return (t, r) => (y(), c(T(j), {
493
+ return (t, r) => (y(), c(T(M), {
494
494
  id: T(n)?.controlId.value ?? e.id,
495
495
  as: "select",
496
496
  class: "fg-select",
@@ -502,7 +502,7 @@ var V = { class: "fg-card" }, H = {
502
502
  value: e.modelValue,
503
503
  onChange: i
504
504
  }, {
505
- default: k(() => [S(t.$slots, "default")]),
505
+ default: A(() => [S(t.$slots, "default")]),
506
506
  _: 3
507
507
  }, 8, [
508
508
  "id",
@@ -514,7 +514,7 @@ var V = { class: "fg-card" }, H = {
514
514
  "value"
515
515
  ]));
516
516
  }
517
- }), Ve = /* @__PURE__ */ m({
517
+ }), He = /* @__PURE__ */ m({
518
518
  __name: "UiSlider",
519
519
  props: {
520
520
  disabled: {
@@ -547,7 +547,7 @@ var V = { class: "fg-card" }, H = {
547
547
  e !== void 0 && i("update:modelValue", e);
548
548
  }
549
549
  });
550
- return (t, i) => (y(), c(T(L), {
550
+ return (t, i) => (y(), c(T(R), {
551
551
  modelValue: a.value,
552
552
  "onUpdate:modelValue": i[0] ||= (e) => a.value = e,
553
553
  class: "fg-slider",
@@ -557,10 +557,10 @@ var V = { class: "fg-card" }, H = {
557
557
  min: r.value.min,
558
558
  step: r.value.step
559
559
  }, {
560
- default: k(() => [p(T(z), { class: "fg-slider__track" }, {
561
- default: k(() => [p(T(I), { class: "fg-slider__range" })]),
560
+ default: A(() => [p(T(B), { class: "fg-slider__track" }, {
561
+ default: A(() => [p(T(L), { class: "fg-slider__range" })]),
562
562
  _: 1
563
- }), p(T(R), {
563
+ }), p(T(z), {
564
564
  id: T(n)?.controlId.value ?? e.id,
565
565
  class: "fg-slider__thumb",
566
566
  "aria-describedby": T(n)?.descriptionId.value,
@@ -584,10 +584,73 @@ var V = { class: "fg-card" }, H = {
584
584
  "step"
585
585
  ]));
586
586
  }
587
- }), He = { class: "fg-toggle-button__text" }, Ue = { class: "fg-toggle-button__label" }, We = {
587
+ }), Ue = ["data-size", "data-disabled"], We = [
588
+ "id",
589
+ "aria-checked",
590
+ "aria-describedby",
591
+ "aria-errormessage",
592
+ "aria-invalid",
593
+ "disabled"
594
+ ], Ge = {
595
+ key: 0,
596
+ class: "fg-switch__text"
597
+ }, Ke = ["for"], qe = ["id"], Je = /* @__PURE__ */ m({
598
+ inheritAttrs: !1,
599
+ __name: "UiSwitch",
600
+ props: {
601
+ description: { default: () => void 0 },
602
+ disabled: {
603
+ type: Boolean,
604
+ default: !1
605
+ },
606
+ id: { default: () => void 0 },
607
+ label: { default: () => void 0 },
608
+ modelValue: {
609
+ type: Boolean,
610
+ default: !1
611
+ },
612
+ size: { default: "md" }
613
+ },
614
+ emits: ["update:modelValue"],
615
+ setup(e, { emit: t }) {
616
+ let n = t, r = k(), i = E(), a = h(Z, void 0), o = D(), c = s(() => a?.controlId.value ?? e.id ?? o), p = s(() => `${c.value}-switch-description`), m = () => [
617
+ i["aria-describedby"],
618
+ a?.descriptionId.value,
619
+ e.description ? p.value : void 0
620
+ ].filter(Boolean).join(" ") || void 0, g = () => {
621
+ e.disabled || n("update:modelValue", !e.modelValue);
622
+ };
623
+ return (t, n) => (y(), u("div", {
624
+ class: "fg-switch",
625
+ "data-size": e.size,
626
+ "data-disabled": e.disabled ? "true" : void 0
627
+ }, [d("button", _(T(i), {
628
+ id: c.value,
629
+ class: "fg-switch__control",
630
+ type: "button",
631
+ role: "switch",
632
+ "aria-checked": e.modelValue,
633
+ "aria-describedby": m(),
634
+ "aria-errormessage": T(a)?.errorId.value,
635
+ "aria-invalid": T(a)?.invalid.value ? "true" : void 0,
636
+ disabled: e.disabled,
637
+ onClick: g
638
+ }), [...n[0] ||= [d("span", {
639
+ class: "fg-switch__track",
640
+ "aria-hidden": "true"
641
+ }, null, -1)]], 16, We), r.default || e.label || e.description ? (y(), u("span", Ge, [r.default || e.label ? (y(), u("label", {
642
+ key: 0,
643
+ for: c.value
644
+ }, [S(t.$slots, "default", {}, () => [f(w(e.label), 1)])], 8, Ke)) : l("", !0), e.description ? (y(), u("span", {
645
+ key: 1,
646
+ id: p.value,
647
+ class: "fg-switch__description"
648
+ }, w(e.description), 9, qe)) : l("", !0)])) : l("", !0)], 8, Ue));
649
+ }
650
+ }), Ye = { class: "fg-toggle-button__text" }, Xe = { class: "fg-toggle-button__label" }, Ze = {
588
651
  key: 0,
589
652
  class: "fg-toggle-button__description"
590
- }, Ge = /* @__PURE__ */ m({
653
+ }, Qe = /* @__PURE__ */ m({
591
654
  __name: "UiToggleButton",
592
655
  props: {
593
656
  disabled: {
@@ -602,20 +665,20 @@ var V = { class: "fg-card" }, H = {
602
665
  },
603
666
  emits: ["update:pressed"],
604
667
  setup(e, { emit: t }) {
605
- let n = t, r = O(), i = (e) => {
668
+ let n = t, r = k(), i = (e) => {
606
669
  n("update:pressed", e);
607
670
  };
608
- return (t, n) => (y(), c(T(B), {
671
+ return (t, n) => (y(), c(T(V), {
609
672
  class: "fg-toggle-button",
610
673
  "data-size": e.size,
611
674
  disabled: e.disabled,
612
675
  "model-value": e.pressed,
613
676
  "onUpdate:modelValue": i
614
677
  }, {
615
- default: k(() => [n[0] ||= d("span", {
678
+ default: A(() => [n[0] ||= d("span", {
616
679
  class: "fg-toggle-button__switch",
617
680
  "aria-hidden": "true"
618
- }, null, -1), d("span", He, [d("span", Ue, [S(t.$slots, "default")]), r.description ? (y(), u("span", We, [S(t.$slots, "description")])) : l("", !0)])]),
681
+ }, null, -1), d("span", Ye, [d("span", Xe, [S(t.$slots, "default")]), r.description ? (y(), u("span", Ze, [S(t.$slots, "description")])) : l("", !0)])]),
619
682
  _: 3
620
683
  }, 8, [
621
684
  "data-size",
@@ -623,22 +686,22 @@ var V = { class: "fg-card" }, H = {
623
686
  "model-value"
624
687
  ]));
625
688
  }
626
- }), Ke = /* @__PURE__ */ m({
689
+ }), $e = /* @__PURE__ */ m({
627
690
  __name: "UiSurface",
628
691
  props: {
629
692
  as: { default: "section" },
630
693
  padding: { default: "default" }
631
694
  },
632
695
  setup(e) {
633
- return (t, n) => (y(), c(T(j), {
696
+ return (t, n) => (y(), c(T(M), {
634
697
  as: e.as,
635
698
  class: "fg-surface",
636
699
  "data-padding": e.padding
637
700
  }, {
638
- default: k(() => [S(t.$slots, "default")]),
701
+ default: A(() => [S(t.$slots, "default")]),
639
702
  _: 3
640
703
  }, 8, ["as", "data-padding"]));
641
704
  }
642
705
  });
643
706
  //#endregion
644
- export { me as UiAlert, he as UiBadge, r as UiButton, K as UiCard, ve as UiCheckbox, pe as UiCodeBlock, t as UiDialog, i as UiDrawer, Ce as UiField, Oe as UiFigure, ke as UiInput, je as UiProgress, Ne as UiRadioCard, Pe as UiRadioCardGroup, ze as UiScore, Be as UiSelect, Ve as UiSlider, Ke as UiSurface, n as UiTabs, Ge as UiToggleButton, a as useActiveSection };
707
+ export { he as UiAlert, ge as UiBadge, r as UiButton, q as UiCard, ye as UiCheckbox, me as UiCodeBlock, t as UiDialog, i as UiDrawer, we as UiField, ke as UiFigure, Ae as UiInput, Me as UiProgress, Pe as UiRadioCard, Fe as UiRadioCardGroup, Ve as UiScore, $ as UiSelect, He as UiSlider, $e as UiSurface, Je as UiSwitch, n as UiTabs, Qe as UiToggleButton, a as useActiveSection };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filipgutica/ui",
3
- "version": "1.12.0",
3
+ "version": "1.13.1",
4
4
  "description": "A compact Vue design system with Tailwind CSS and VS Code theme support",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -5,7 +5,7 @@
5
5
  /* Package-owned typography keeps controls consistent across consuming apps. */
6
6
  .fg-button, .fg-input, .fg-select, .fg-checkbox, .fg-field,
7
7
  .fg-radio-card, .fg-badge, .fg-alert, .fg-surface, .fg-card,
8
- .fg-dialog__content, .fg-code-block, .fg-toggle-button {
8
+ .fg-dialog__content, .fg-code-block, .fg-toggle-button, .fg-switch {
9
9
  font-family: var(--font-ui);
10
10
  font-size: var(--text-md);
11
11
  font-weight: var(--weight-regular);
@@ -171,6 +171,7 @@
171
171
  .fg-input:disabled,
172
172
  .fg-select:disabled,
173
173
  .fg-checkbox[data-disabled="true"],
174
+ .fg-switch[data-disabled="true"],
174
175
  .fg-toggle-button:disabled {
175
176
  cursor: not-allowed;
176
177
  opacity: 0.58;
@@ -717,8 +718,35 @@
717
718
  .fg-toggle-button:hover:not(:disabled, [aria-pressed="true"]) { border-color: var(--color-border); }
718
719
  .fg-toggle-button[aria-pressed="true"] { border-color: var(--color-accent); }
719
720
 
720
- /* The thumb's position, not only its color, shows the state. */
721
- .fg-toggle-button__switch {
721
+ .fg-switch { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
722
+ .fg-switch__control {
723
+ display: inline-flex;
724
+ align-items: center;
725
+ justify-content: center;
726
+ flex: none;
727
+ min-width: var(--control-sm);
728
+ min-height: var(--control-md);
729
+ padding: 0;
730
+ border: 0;
731
+ background: transparent;
732
+ cursor: pointer;
733
+ }
734
+ .fg-switch[data-size="sm"] { font-size: var(--text-sm); }
735
+ .fg-switch[data-size="sm"] .fg-switch__control { min-height: var(--control-sm); }
736
+ .fg-switch[data-size="lg"] { font-size: var(--text-lg); }
737
+ .fg-switch[data-size="lg"] .fg-switch__control { min-height: var(--control-lg); }
738
+ /* The visible track scales with size; the thumb travels the track width minus its height. */
739
+ .fg-switch { --fg-switch-width: 2.25rem; --fg-switch-height: 1.25rem; }
740
+ .fg-switch[data-size="sm"] { --fg-switch-width: 1.75rem; --fg-switch-height: 1rem; }
741
+ .fg-switch[data-size="lg"] { --fg-switch-width: 2.75rem; --fg-switch-height: 1.5rem; }
742
+ .fg-switch__text { display: grid; min-width: 0; overflow-wrap: anywhere; }
743
+ .fg-switch__text label { cursor: pointer; }
744
+ .fg-switch[data-disabled="true"] :is(button, label) { cursor: not-allowed; }
745
+ .fg-switch__description { color: var(--color-muted); font-size: var(--text-sm); }
746
+
747
+ /* Both toggle controls share the track; thumb position also shows the state. */
748
+ .fg-toggle-button__switch,
749
+ .fg-switch__track {
722
750
  position: relative;
723
751
  flex: none;
724
752
  width: 1.75rem;
@@ -729,7 +757,8 @@
729
757
  transition: background-color var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
730
758
  }
731
759
 
732
- .fg-toggle-button__switch::after {
760
+ .fg-toggle-button__switch::after,
761
+ .fg-switch__track::after {
733
762
  position: absolute;
734
763
  top: 0.125rem;
735
764
  left: 0.125rem;
@@ -741,16 +770,24 @@
741
770
  transition: transform var(--duration) var(--ease-out), background-color var(--duration) var(--ease-out);
742
771
  }
743
772
 
744
- .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch {
773
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch,
774
+ .fg-switch__control[aria-checked="true"] .fg-switch__track {
745
775
  border-color: var(--color-accent);
746
776
  background: var(--color-accent);
747
777
  }
748
778
 
749
- .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch::after {
779
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch::after,
780
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after {
750
781
  background: var(--color-accent-text);
751
782
  transform: translateX(0.75rem);
752
783
  }
753
784
 
785
+ .fg-switch__track { box-sizing: border-box; width: var(--fg-switch-width); height: var(--fg-switch-height); }
786
+ .fg-switch__track::after { width: calc(var(--fg-switch-height) - 0.375rem); height: calc(var(--fg-switch-height) - 0.375rem); }
787
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after {
788
+ transform: translateX(calc(var(--fg-switch-width) - var(--fg-switch-height)));
789
+ }
790
+
754
791
  .fg-toggle-button__text { display: grid; min-width: 0; }
755
792
 
756
793
  .fg-toggle-button__description {
@@ -902,11 +939,15 @@
902
939
  .fg-slider__thumb:focus-visible,
903
940
  .fg-dialog__close:focus-visible,
904
941
  .fg-dialog__content:focus-visible,
905
- .fg-toggle-button:focus-visible {
942
+ .fg-toggle-button:focus-visible,
943
+ .fg-switch__control:focus-visible .fg-switch__track {
906
944
  outline: 2px solid var(--color-focus);
907
945
  outline-offset: 2px;
908
946
  }
909
947
 
948
+ /* The control is a larger transparent hit area, so the ring follows the visible track instead. */
949
+ .fg-switch__control:focus-visible { outline: none; }
950
+
910
951
  :root.high-contrast .fg-button,
911
952
  :root.high-contrast .fg-input,
912
953
  :root.high-contrast .fg-select,
@@ -934,6 +975,13 @@
934
975
  }
935
976
  }
936
977
 
978
+ @media (forced-colors: active) {
979
+ .fg-switch__track { border-color: ButtonText; background: Canvas; }
980
+ .fg-switch__track::after { background: ButtonText; }
981
+ .fg-switch__control[aria-checked="true"] .fg-switch__track { border-color: Highlight; background: Highlight; forced-color-adjust: none; }
982
+ .fg-switch__control[aria-checked="true"] .fg-switch__track::after { background: HighlightText; }
983
+ }
984
+
937
985
  @media (prefers-reduced-motion: reduce) {
938
986
  .fg-button,
939
987
  .fg-input,
@@ -943,7 +991,9 @@
943
991
  .fg-dialog__close,
944
992
  .fg-progress__indicator,
945
993
  .fg-toggle-button__switch,
946
- .fg-toggle-button__switch::after { transition: none; }
994
+ .fg-toggle-button__switch::after,
995
+ .fg-switch__track,
996
+ .fg-switch__track::after { transition: none; }
947
997
 
948
998
  .fg-button[aria-busy="true"]::before { animation-duration: 1.4s; }
949
999
  }
package/src/site.css CHANGED
@@ -554,8 +554,10 @@
554
554
  font-size: var(--text-sm);
555
555
  }
556
556
  .fg-site-facts { font-family: var(--font-mono); }
557
- .fg-site-facts > div { display: flex; gap: var(--space-2); }
558
- .fg-site-facts dd { margin: 0; color: var(--color-text); }
557
+ /* A label and a long value, such as a repository path, wrap at large text sizes instead of
558
+ * widening the page. */
559
+ .fg-site-facts > div { display: flex; flex-wrap: wrap; column-gap: var(--space-2); }
560
+ .fg-site-facts dd { min-width: 0; margin: 0; color: var(--color-text); overflow-wrap: anywhere; }
559
561
  .fg-site-definitions {
560
562
  display: grid;
561
563
  grid-template-columns: 9rem minmax(0, 1fr);
@@ -718,7 +720,7 @@
718
720
  * moves a full target below the one before it, so their targets never overlap. */
719
721
  .fg-site-facts { row-gap: var(--space-2); }
720
722
  .fg-site-facts > div:has(a) ~ div:has(a) { margin-top: calc(var(--control-lg) - 1lh - var(--space-2)); }
721
- .fg-site-facts a { position: relative; display: inline-block; }
723
+ .fg-site-facts a { position: relative; display: inline-block; max-width: 100%; }
722
724
  .fg-site-facts a::after {
723
725
  content: '';
724
726
  position: absolute;