@filipgutica/ui 1.7.0 → 1.8.0

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,16 @@
1
+ export interface UiFigureProps {
2
+ number?: number;
3
+ }
4
+ type __VLS_Slots = {
5
+ caption?(): unknown;
6
+ default?(): unknown;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<UiFigureProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<UiFigureProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,7 @@
1
+ export interface UiScoreProps {
2
+ max?: number;
3
+ score: number;
4
+ }
5
+ declare const __VLS_export: import("vue").DefineComponent<UiScoreProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<UiScoreProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import type { UiControlSize } from '../control.js';
2
+ export interface UiToggleButtonProps {
3
+ disabled?: boolean;
4
+ pressed?: boolean;
5
+ size?: UiControlSize;
6
+ }
7
+ type __VLS_Slots = {
8
+ default?(): unknown;
9
+ description?(): unknown;
10
+ };
11
+ declare const __VLS_base: import("vue").DefineComponent<UiToggleButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
12
+ "update:pressed": (value: boolean) => any;
13
+ }, string, import("vue").PublicProps, Readonly<UiToggleButtonProps> & Readonly<{
14
+ "onUpdate:pressed"?: (value: boolean) => any;
15
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
17
+ declare const _default: typeof __VLS_export;
18
+ export default _default;
19
+ type __VLS_WithSlots<T, S> = T & {
20
+ new (): {
21
+ $slots: S;
22
+ };
23
+ };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export { default as UiDrawer } from './components/UiDrawer.vue';
16
16
  export type { UiDrawerProps } from './components/UiDrawer.vue';
17
17
  export { default as UiField } from './components/UiField.vue';
18
18
  export type { UiFieldProps } from './components/UiField.vue';
19
+ export { default as UiFigure } from './components/UiFigure.vue';
20
+ export type { UiFigureProps } from './components/UiFigure.vue';
19
21
  export { default as UiInput } from './components/UiInput.vue';
20
22
  export type { UiInputProps } from './components/UiInput.vue';
21
23
  export { default as UiProgress } from './components/UiProgress.vue';
@@ -24,12 +26,16 @@ export { default as UiRadioCard } from './components/UiRadioCard.vue';
24
26
  export type { UiRadioCardProps } from './components/UiRadioCard.vue';
25
27
  export { default as UiRadioCardGroup } from './components/UiRadioCardGroup.vue';
26
28
  export type { UiRadioCardGroupProps } from './components/UiRadioCardGroup.vue';
29
+ export { default as UiScore } from './components/UiScore.vue';
30
+ export type { UiScoreProps } from './components/UiScore.vue';
27
31
  export { default as UiSelect } from './components/UiSelect.vue';
28
32
  export type { UiSelectProps } from './components/UiSelect.vue';
29
33
  export { default as UiSlider } from './components/UiSlider.vue';
30
34
  export type { UiSliderProps } from './components/UiSlider.vue';
31
35
  export { default as UiTabs } from './components/UiTabs.vue';
32
36
  export type { UiTabItem, UiTabsProps } from './components/UiTabs.vue';
37
+ export { default as UiToggleButton } from './components/UiToggleButton.vue';
38
+ export type { UiToggleButtonProps } from './components/UiToggleButton.vue';
33
39
  /** @deprecated Use UiCard for structured content. */
34
40
  export { default as UiSurface } from './components/UiSurface.vue';
35
41
  export type { UiSurfaceProps } from './components/UiSurface.vue';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./use-active-section-CiflgGBI.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 x, renderList as S, renderSlot as C, resolveDynamicComponent as w, shallowRef as T, toDisplayString as E, unref as D, useModel as ee, useSlots as te, watch as O, withCtx as k } from "vue";
3
- import { CheckboxIndicator as A, 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 } 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, useId as E, useModel as ne, useSlots as D, watch as re, withCtx as O } from "vue";
3
+ import { CheckboxIndicator as k, 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";
4
4
  //#region src/components/UiCard.vue?vue&type=script&setup=true&lang.ts
5
5
  var V = { class: "fg-card" }, H = {
6
6
  key: 0,
@@ -21,17 +21,17 @@ var V = { class: "fg-card" }, H = {
21
21
  titleTag: { default: "h3" }
22
22
  },
23
23
  setup(e) {
24
- let t = te();
24
+ let t = D();
25
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(w(e.titleTag), {
26
+ e.title || t.title || t.actions ? (y(), u("header", H, [e.title || t.title ? (y(), c(C(e.titleTag), {
27
27
  key: 0,
28
28
  class: "fg-card__title"
29
29
  }, {
30
- default: k(() => [C(n.$slots, "title", {}, () => [f(E(e.title), 1)])]),
30
+ default: O(() => [S(n.$slots, "title", {}, () => [f(w(e.title), 1)])]),
31
31
  _: 3
32
- })) : l("", !0), t.actions ? (y(), u("div", U, [C(n.$slots, "actions")])) : l("", !0)])) : l("", !0),
33
- t.default ? (y(), u("div", W, [C(n.$slots, "default")])) : l("", !0),
34
- t.footer ? (y(), u("footer", G, [C(n.$slots, "footer")])) : l("", !0)
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)
35
35
  ]));
36
36
  }
37
37
  }), q = [
@@ -47,20 +47,20 @@ var V = { class: "fg-card" }, H = {
47
47
  }, X = {
48
48
  key: 1,
49
49
  class: "fg-code-block__language"
50
- }, Z = { class: "fg-code-block__actions" }, ne = ["disabled", "title"], re = {
50
+ }, ie = { class: "fg-code-block__actions" }, ae = ["disabled", "title"], oe = {
51
51
  viewBox: "0 0 24 24",
52
52
  fill: "none",
53
53
  stroke: "currentColor",
54
54
  "stroke-width": "1.5",
55
55
  "aria-hidden": "true"
56
- }, ie = {
56
+ }, se = {
57
57
  key: 0,
58
58
  d: "m5 12 4 4L19 6"
59
- }, ae = { key: 0 }, oe = ["aria-label"], se = {
59
+ }, ce = { key: 0 }, le = ["aria-label"], ue = {
60
60
  key: 0,
61
61
  class: "fg-code-block__number",
62
62
  "aria-hidden": "true"
63
- }, ce = { class: "fg-code-block__text" }, le = ["data-state"], ue = /* @__PURE__ */ m({
63
+ }, de = { class: "fg-code-block__text" }, fe = ["data-state"], pe = /* @__PURE__ */ m({
64
64
  __name: "UiCodeBlock",
65
65
  props: {
66
66
  code: {},
@@ -81,7 +81,7 @@ var V = { class: "fg-card" }, H = {
81
81
  variant: { default: "default" }
82
82
  },
83
83
  setup(t) {
84
- let n = T(), r = x(""), i = s(() => n.value ?? t.code.split("\n").map((e) => [{ content: e }])), a = {
84
+ let n = te(), r = ee(""), i = s(() => n.value ?? t.code.split("\n").map((e) => [{ content: e }])), a = {
85
85
  vue: "vue",
86
86
  ts: "typescript",
87
87
  typescript: "typescript",
@@ -94,7 +94,7 @@ var V = { class: "fg-card" }, H = {
94
94
  sh: "bash",
95
95
  shell: "bash"
96
96
  };
97
- O(() => [t.code, t.language], async ([e, t], i, o) => {
97
+ re(() => [t.code, t.language], async ([e, t], i, o) => {
98
98
  let s = !1;
99
99
  o(() => {
100
100
  s = !0;
@@ -120,7 +120,7 @@ var V = { class: "fg-card" }, H = {
120
120
  let { copied: c, pending: p, error: m, copy: h } = e({
121
121
  unavailableMessage: "Clipboard unavailable. Select the code to copy it.",
122
122
  failureMessage: "Could not copy. Select the code to copy it."
123
- }), g = s(() => c.value && !m.value), _ = s(() => t.variant === "compact" && g.value && !r.value), b = s(() => m.value ? m.value : t.variant === "compact" && r.value ? c.value ? `Code copied to clipboard. ${r.value}` : r.value : c.value ? "Code copied to clipboard." : r.value), w = () => h(t.code);
123
+ }), g = s(() => c.value && !m.value), _ = s(() => t.variant === "compact" && g.value && !r.value), b = s(() => m.value ? m.value : t.variant === "compact" && r.value ? c.value ? `Code copied to clipboard. ${r.value}` : r.value : c.value ? "Code copied to clipboard." : r.value), C = () => h(t.code);
124
124
  return (e, n) => (y(), u("div", {
125
125
  class: "fg-code-block",
126
126
  "data-wrap": t.wrap,
@@ -128,70 +128,70 @@ var V = { class: "fg-card" }, H = {
128
128
  "data-variant": t.variant
129
129
  }, [
130
130
  t.variant === "default" || t.copyable || e.$slots.actions ? (y(), u("div", J, [
131
- t.variant === "default" ? (y(), u("span", Y, E(t.title || t.language), 1)) : l("", !0),
132
- t.title && t.variant === "default" ? (y(), u("span", X, E(t.language), 1)) : l("", !0),
133
- d("div", Z, [C(e.$slots, "actions"), t.copyable ? (y(), u("button", {
131
+ t.variant === "default" ? (y(), u("span", Y, w(t.title || t.language), 1)) : l("", !0),
132
+ t.title && t.variant === "default" ? (y(), u("span", X, w(t.language), 1)) : l("", !0),
133
+ d("div", ie, [S(e.$slots, "actions"), t.copyable ? (y(), u("button", {
134
134
  key: 0,
135
135
  type: "button",
136
136
  class: "fg-code-block__copy",
137
- disabled: D(p),
137
+ disabled: T(p),
138
138
  "aria-label": "Copy code",
139
139
  title: t.variant === "compact" ? g.value ? "Copied" : "Copy code" : void 0,
140
- onClick: w
141
- }, [(y(), u("svg", re, [t.variant === "compact" && g.value ? (y(), u("path", ie)) : (y(), u(o, { key: 1 }, [n[0] ||= d("rect", {
140
+ onClick: C
141
+ }, [(y(), u("svg", oe, [t.variant === "compact" && g.value ? (y(), u("path", se)) : (y(), u(o, { key: 1 }, [n[0] ||= d("rect", {
142
142
  x: "8",
143
143
  y: "8",
144
144
  width: "12",
145
145
  height: "13",
146
146
  rx: "2"
147
- }, null, -1), n[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", ae, E(g.value ? "Copied" : "Copy"), 1)) : l("", !0)], 8, ne)) : l("", !0)])
147
+ }, null, -1), n[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(g.value ? "Copied" : "Copy"), 1)) : l("", !0)], 8, ae)) : l("", !0)])
148
148
  ])) : l("", !0),
149
149
  d("pre", {
150
150
  class: "fg-code-block__pre",
151
151
  tabindex: "0",
152
152
  "aria-label": t.title || `${t.language} code`
153
- }, [d("code", null, [(y(!0), u(o, null, S(i.value, (e, n) => (y(), u("span", {
153
+ }, [d("code", null, [(y(!0), u(o, null, x(i.value, (e, n) => (y(), u("span", {
154
154
  key: n,
155
155
  class: "fg-code-block__line"
156
- }, [t.lineNumbers ? (y(), u("span", se, E(n + 1), 1)) : l("", !0), d("span", ce, [(y(!0), u(o, null, S(e, (e, t) => (y(), u("span", {
156
+ }, [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", {
157
157
  key: t,
158
158
  style: v({ color: e.color })
159
- }, E(e.content), 5))), 128)), f(E(n < i.value.length - 1 ? "\n" : ""), 1)])]))), 128))])], 8, oe),
159
+ }, w(e.content), 5))), 128)), f(w(n < i.value.length - 1 ? "\n" : ""), 1)])]))), 128))])], 8, le),
160
160
  d("span", {
161
161
  class: "fg-code-block__status",
162
162
  role: "status",
163
163
  "data-state": _.value ? "success" : void 0
164
- }, E(b.value), 9, le)
164
+ }, w(b.value), 9, fe)
165
165
  ], 8, q));
166
166
  }
167
- }), de = /* @__PURE__ */ m({
167
+ }), me = /* @__PURE__ */ m({
168
168
  __name: "UiAlert",
169
169
  props: { tone: { default: "neutral" } },
170
170
  setup(e) {
171
- return (t, n) => (y(), c(D(M), {
171
+ return (t, n) => (y(), c(T(j), {
172
172
  as: "div",
173
173
  class: "fg-alert",
174
174
  "data-tone": e.tone,
175
175
  role: e.tone === "danger" || e.tone === "error" ? "alert" : "status"
176
176
  }, {
177
- default: k(() => [C(t.$slots, "default")]),
177
+ default: O(() => [S(t.$slots, "default")]),
178
178
  _: 3
179
179
  }, 8, ["data-tone", "role"]));
180
180
  }
181
- }), fe = /* @__PURE__ */ m({
181
+ }), he = /* @__PURE__ */ m({
182
182
  __name: "UiBadge",
183
183
  props: { tone: { default: "neutral" } },
184
184
  setup(e) {
185
- return (t, n) => (y(), c(D(M), {
185
+ return (t, n) => (y(), c(T(j), {
186
186
  as: "span",
187
187
  class: "fg-badge",
188
188
  "data-tone": e.tone
189
189
  }, {
190
- default: k(() => [C(t.$slots, "default")]),
190
+ default: O(() => [S(t.$slots, "default")]),
191
191
  _: 3
192
192
  }, 8, ["data-tone"]));
193
193
  }
194
- }), pe = ["data-size", "data-disabled"], me = { class: "fg-checkbox__label" }, he = /* @__PURE__ */ m({
194
+ }), ge = ["data-size", "data-disabled"], _e = { class: "fg-checkbox__label" }, ve = /* @__PURE__ */ m({
195
195
  __name: "UiCheckbox",
196
196
  props: {
197
197
  disabled: {
@@ -213,20 +213,20 @@ var V = { class: "fg-card" }, H = {
213
213
  class: "fg-checkbox",
214
214
  "data-size": e.size,
215
215
  "data-disabled": e.disabled ? "true" : void 0
216
- }, [p(D(j), {
216
+ }, [p(T(A), {
217
217
  class: "fg-checkbox__control",
218
218
  disabled: e.disabled,
219
219
  "model-value": e.modelValue,
220
220
  "onUpdate:modelValue": r
221
221
  }, {
222
- default: k(() => [p(D(A), { class: "fg-checkbox__indicator" }, {
223
- default: k(() => [...n[0] ||= [f("✓", -1)]]),
222
+ default: O(() => [p(T(k), { class: "fg-checkbox__indicator" }, {
223
+ default: O(() => [...n[0] ||= [f("✓", -1)]]),
224
224
  _: 1
225
225
  })]),
226
226
  _: 1
227
- }, 8, ["disabled", "model-value"]), d("span", me, [C(t.$slots, "default")])], 8, pe));
227
+ }, 8, ["disabled", "model-value"]), d("span", _e, [S(t.$slots, "default")])], 8, ge));
228
228
  }
229
- }), Q = Symbol("UiFieldContext"), ge = ["data-invalid"], _e = ["for"], ve = ["id"], ye = ["id"], be = /* @__PURE__ */ m({
229
+ }), Z = Symbol("UiFieldContext"), ye = ["data-invalid"], be = ["for"], xe = ["id"], Se = ["id"], Ce = /* @__PURE__ */ m({
230
230
  __name: "UiField",
231
231
  props: {
232
232
  controlId: {},
@@ -236,7 +236,7 @@ var V = { class: "fg-card" }, H = {
236
236
  },
237
237
  setup(e) {
238
238
  let t = s(() => e.description && !e.error ? `${e.controlId}-description` : void 0), n = s(() => e.error ? `${e.controlId}-error` : void 0), r = s(() => !!e.error);
239
- return b(Q, {
239
+ return b(Z, {
240
240
  controlId: s(() => e.controlId),
241
241
  descriptionId: t,
242
242
  errorId: n,
@@ -248,8 +248,8 @@ var V = { class: "fg-card" }, H = {
248
248
  d("label", {
249
249
  class: "fg-field__label",
250
250
  for: e.controlId
251
- }, E(e.label), 9, _e),
252
- C(r.$slots, "default", {
251
+ }, w(e.label), 9, be),
252
+ S(r.$slots, "default", {
253
253
  descriptionId: t.value,
254
254
  errorId: n.value
255
255
  }),
@@ -258,16 +258,40 @@ var V = { class: "fg-card" }, H = {
258
258
  id: t.value,
259
259
  class: "fg-field__description",
260
260
  "data-field-description": ""
261
- }, E(e.description), 9, ve)) : l("", !0),
261
+ }, w(e.description), 9, xe)) : l("", !0),
262
262
  e.error ? (y(), u("p", {
263
263
  key: 1,
264
264
  id: n.value,
265
265
  class: "fg-field__error",
266
266
  "data-field-error": ""
267
- }, E(e.error), 9, ye)) : l("", !0)
268
- ], 8, ge));
267
+ }, w(e.error), 9, Se)) : l("", !0)
268
+ ], 8, ye));
269
269
  }
270
- }), $ = /* @__PURE__ */ m({
270
+ }), we = { class: "fg-figure" }, Te = ["aria-labelledby", "aria-label"], Ee = ["id"], De = {
271
+ key: 0,
272
+ class: "fg-figure__number"
273
+ }, Oe = /* @__PURE__ */ m({
274
+ __name: "UiFigure",
275
+ props: { number: { default: () => void 0 } },
276
+ setup(e) {
277
+ let t = D(), n = E(), r = () => e.number !== void 0 || !!t.caption;
278
+ return (t, i) => (y(), u("figure", we, [d("div", {
279
+ class: "fg-figure__plate",
280
+ role: "region",
281
+ tabindex: "0",
282
+ "aria-labelledby": r() ? T(n) : void 0,
283
+ "aria-label": r() ? void 0 : "Figure"
284
+ }, [S(t.$slots, "default")], 8, Te), r() ? (y(), u("figcaption", {
285
+ key: 0,
286
+ id: T(n),
287
+ class: "fg-figure__caption"
288
+ }, [
289
+ e.number === void 0 ? l("", !0) : (y(), u("span", De, "Figure " + w(e.number) + ".", 1)),
290
+ i[0] ||= f(),
291
+ S(t.$slots, "caption")
292
+ ], 8, Ee)) : l("", !0)]));
293
+ }
294
+ }), ke = /* @__PURE__ */ m({
271
295
  __name: "UiInput",
272
296
  props: {
273
297
  disabled: {
@@ -285,16 +309,16 @@ var V = { class: "fg-card" }, H = {
285
309
  },
286
310
  emits: ["update:modelValue"],
287
311
  setup(e, { emit: t }) {
288
- let n = h(Q, void 0), r = t, i = (e) => {
312
+ let n = h(Z, void 0), r = t, i = (e) => {
289
313
  e.currentTarget instanceof HTMLInputElement && r("update:modelValue", e.currentTarget.value);
290
314
  };
291
- return (t, r) => (y(), c(D(M), {
292
- id: D(n)?.controlId.value ?? e.id,
315
+ return (t, r) => (y(), c(T(j), {
316
+ id: T(n)?.controlId.value ?? e.id,
293
317
  as: "input",
294
318
  class: "fg-input",
295
- "aria-describedby": D(n)?.descriptionId.value,
296
- "aria-errormessage": D(n)?.errorId.value,
297
- "aria-invalid": e.invalid || D(n)?.invalid.value ? "true" : void 0,
319
+ "aria-describedby": T(n)?.descriptionId.value,
320
+ "aria-errormessage": T(n)?.errorId.value,
321
+ "aria-invalid": e.invalid || T(n)?.invalid.value ? "true" : void 0,
298
322
  "data-size": e.size,
299
323
  disabled: e.disabled,
300
324
  type: e.type,
@@ -311,7 +335,7 @@ var V = { class: "fg-card" }, H = {
311
335
  "value"
312
336
  ]));
313
337
  }
314
- }), xe = 100, Se = /* @__PURE__ */ m({
338
+ }), Ae = 100, je = /* @__PURE__ */ m({
315
339
  __name: "UiProgress",
316
340
  props: {
317
341
  label: {},
@@ -320,19 +344,19 @@ var V = { class: "fg-card" }, H = {
320
344
  },
321
345
  setup(e) {
322
346
  let t = s(() => {
323
- let t = Number.isFinite(e.max) && e.max > 0 ? e.max : xe;
347
+ let t = Number.isFinite(e.max) && e.max > 0 ? e.max : Ae;
324
348
  return {
325
349
  max: t,
326
350
  value: e.value === null || !Number.isFinite(e.value) ? null : Math.min(t, Math.max(0, e.value))
327
351
  };
328
352
  }), n = s(() => t.value.value === null ? 0 : t.value.value / t.value.max * 100);
329
- return (r, i) => (y(), c(D(P), {
353
+ return (r, i) => (y(), c(T(N), {
330
354
  class: "fg-progress",
331
355
  "aria-label": e.label,
332
356
  max: t.value.max,
333
357
  "model-value": t.value.value
334
358
  }, {
335
- default: k(() => [p(D(N), {
359
+ default: O(() => [p(T(M), {
336
360
  class: "fg-progress__indicator",
337
361
  style: v({ transform: `translateX(-${100 - n.value}%)` })
338
362
  }, null, 8, ["style"])]),
@@ -343,7 +367,7 @@ var V = { class: "fg-card" }, H = {
343
367
  "model-value"
344
368
  ]));
345
369
  }
346
- }), Ce = { class: "fg-radio-card__content" }, we = /* @__PURE__ */ m({
370
+ }), Me = { class: "fg-radio-card__content" }, Ne = /* @__PURE__ */ m({
347
371
  __name: "UiRadioCard",
348
372
  props: {
349
373
  disabled: {
@@ -353,19 +377,19 @@ var V = { class: "fg-card" }, H = {
353
377
  value: {}
354
378
  },
355
379
  setup(e) {
356
- return (t, n) => (y(), c(D(F), {
380
+ return (t, n) => (y(), c(T(P), {
357
381
  class: "fg-radio-card",
358
382
  disabled: e.disabled,
359
383
  value: e.value
360
384
  }, {
361
- default: k(() => [n[0] ||= d("span", {
385
+ default: O(() => [n[0] ||= d("span", {
362
386
  class: "fg-radio-card__indicator",
363
387
  "aria-hidden": "true"
364
- }, null, -1), d("span", Ce, [C(t.$slots, "default")])]),
388
+ }, null, -1), d("span", Me, [S(t.$slots, "default")])]),
365
389
  _: 3
366
390
  }, 8, ["disabled", "value"]));
367
391
  }
368
- }), Te = /* @__PURE__ */ m({
392
+ }), Pe = /* @__PURE__ */ m({
369
393
  __name: "UiRadioCardGroup",
370
394
  props: /*@__PURE__*/ g({
371
395
  disabled: {
@@ -383,7 +407,7 @@ var V = { class: "fg-card" }, H = {
383
407
  }),
384
408
  emits: ["update:modelValue"],
385
409
  setup(e) {
386
- let t = ee(e, "modelValue"), n = (t) => {
410
+ let t = ne(e, "modelValue"), n = (t) => {
387
411
  if (t.altKey || t.ctrlKey || t.metaKey || t.shiftKey) return;
388
412
  let n = t.currentTarget, r = t.target;
389
413
  if (!(n instanceof HTMLElement) || !(r instanceof HTMLElement)) return;
@@ -399,14 +423,14 @@ var V = { class: "fg-card" }, H = {
399
423
  let d = o[u];
400
424
  !d || d === r || (t.preventDefault(), d.focus(), d.click());
401
425
  };
402
- return (r, i) => (y(), c(D(I), _({
426
+ return (r, i) => (y(), c(T(F), _({
403
427
  modelValue: t.value,
404
428
  "onUpdate:modelValue": i[0] ||= (e) => t.value = e,
405
429
  class: "fg-radio-card-group",
406
430
  disabled: e.disabled,
407
431
  loop: e.loop
408
432
  }, e.orientation === void 0 ? {} : { orientation: e.orientation }, { onKeydown: n }), {
409
- default: k(() => [C(r.$slots, "default")]),
433
+ default: O(() => [S(r.$slots, "default")]),
410
434
  _: 3
411
435
  }, 16, [
412
436
  "modelValue",
@@ -414,7 +438,30 @@ var V = { class: "fg-card" }, H = {
414
438
  "loop"
415
439
  ]));
416
440
  }
417
- }), Ee = /* @__PURE__ */ m({
441
+ }), Fe = { class: "fg-score" }, Q = {
442
+ class: "fg-score__pips",
443
+ "aria-hidden": "true"
444
+ }, Ie = ["data-filled"], Le = { class: "fg-score__value" }, Re = { class: "fg-score__max" }, $ = 3, ze = /* @__PURE__ */ m({
445
+ __name: "UiScore",
446
+ props: {
447
+ max: { default: () => $ },
448
+ score: {}
449
+ },
450
+ setup(e) {
451
+ let t = s(() => {
452
+ let t = Number.isInteger(e.max) && e.max > 0 ? e.max : $;
453
+ return {
454
+ max: t,
455
+ score: Number.isFinite(e.score) ? Math.min(t, Math.max(0, e.score)) : 0
456
+ };
457
+ });
458
+ return (e, n) => (y(), u("span", Fe, [d("span", Q, [(y(!0), u(o, null, x(t.value.max, (e) => (y(), u("span", {
459
+ key: e,
460
+ class: "fg-score__pip",
461
+ "data-filled": e <= t.value.score ? "true" : void 0
462
+ }, null, 8, Ie))), 128))]), d("span", Le, [f(w(t.value.score), 1), d("span", Re, "/" + w(t.value.max), 1)])]));
463
+ }
464
+ }), Be = /* @__PURE__ */ m({
418
465
  __name: "UiSelect",
419
466
  props: {
420
467
  disabled: {
@@ -431,22 +478,22 @@ var V = { class: "fg-card" }, H = {
431
478
  },
432
479
  emits: ["update:modelValue"],
433
480
  setup(e, { emit: t }) {
434
- let n = h(Q, void 0), r = t, i = (e) => {
481
+ let n = h(Z, void 0), r = t, i = (e) => {
435
482
  e.currentTarget instanceof HTMLSelectElement && r("update:modelValue", e.currentTarget.value);
436
483
  };
437
- return (t, r) => (y(), c(D(M), {
438
- id: D(n)?.controlId.value ?? e.id,
484
+ return (t, r) => (y(), c(T(j), {
485
+ id: T(n)?.controlId.value ?? e.id,
439
486
  as: "select",
440
487
  class: "fg-select",
441
- "aria-describedby": D(n)?.descriptionId.value,
442
- "aria-errormessage": D(n)?.errorId.value,
443
- "aria-invalid": e.invalid || D(n)?.invalid.value ? "true" : void 0,
488
+ "aria-describedby": T(n)?.descriptionId.value,
489
+ "aria-errormessage": T(n)?.errorId.value,
490
+ "aria-invalid": e.invalid || T(n)?.invalid.value ? "true" : void 0,
444
491
  "data-size": e.size,
445
492
  disabled: e.disabled,
446
493
  value: e.modelValue,
447
494
  onChange: i
448
495
  }, {
449
- default: k(() => [C(t.$slots, "default")]),
496
+ default: O(() => [S(t.$slots, "default")]),
450
497
  _: 3
451
498
  }, 8, [
452
499
  "id",
@@ -458,7 +505,7 @@ var V = { class: "fg-card" }, H = {
458
505
  "value"
459
506
  ]));
460
507
  }
461
- }), De = /* @__PURE__ */ m({
508
+ }), Ve = /* @__PURE__ */ m({
462
509
  __name: "UiSlider",
463
510
  props: {
464
511
  disabled: {
@@ -475,7 +522,7 @@ var V = { class: "fg-card" }, H = {
475
522
  },
476
523
  emits: ["update:modelValue"],
477
524
  setup(e, { emit: t }) {
478
- let n = h(Q, void 0), r = s(() => {
525
+ let n = h(Z, void 0), r = s(() => {
479
526
  let t = Number.isFinite(e.min) ? e.min : 0;
480
527
  return {
481
528
  max: Number.isFinite(e.max) && e.max > t ? e.max : t + 100,
@@ -491,7 +538,7 @@ var V = { class: "fg-card" }, H = {
491
538
  e !== void 0 && i("update:modelValue", e);
492
539
  }
493
540
  });
494
- return (t, i) => (y(), c(D(R), {
541
+ return (t, i) => (y(), c(T(L), {
495
542
  modelValue: a.value,
496
543
  "onUpdate:modelValue": i[0] ||= (e) => a.value = e,
497
544
  class: "fg-slider",
@@ -501,15 +548,15 @@ var V = { class: "fg-card" }, H = {
501
548
  min: r.value.min,
502
549
  step: r.value.step
503
550
  }, {
504
- default: k(() => [p(D(B), { class: "fg-slider__track" }, {
505
- default: k(() => [p(D(L), { class: "fg-slider__range" })]),
551
+ default: O(() => [p(T(z), { class: "fg-slider__track" }, {
552
+ default: O(() => [p(T(I), { class: "fg-slider__range" })]),
506
553
  _: 1
507
- }), p(D(z), {
508
- id: D(n)?.controlId.value ?? e.id,
554
+ }), p(T(R), {
555
+ id: T(n)?.controlId.value ?? e.id,
509
556
  class: "fg-slider__thumb",
510
- "aria-describedby": D(n)?.descriptionId.value,
511
- "aria-errormessage": D(n)?.errorId.value,
512
- "aria-invalid": D(n)?.invalid.value ? "true" : void 0,
557
+ "aria-describedby": T(n)?.descriptionId.value,
558
+ "aria-errormessage": T(n)?.errorId.value,
559
+ "aria-invalid": T(n)?.invalid.value ? "true" : void 0,
513
560
  "aria-label": e.label
514
561
  }, null, 8, [
515
562
  "id",
@@ -528,22 +575,61 @@ var V = { class: "fg-card" }, H = {
528
575
  "step"
529
576
  ]));
530
577
  }
531
- }), Oe = /* @__PURE__ */ m({
578
+ }), He = { class: "fg-toggle-button__text" }, Ue = { class: "fg-toggle-button__label" }, We = {
579
+ key: 0,
580
+ class: "fg-toggle-button__description"
581
+ }, Ge = /* @__PURE__ */ m({
582
+ __name: "UiToggleButton",
583
+ props: {
584
+ disabled: {
585
+ type: Boolean,
586
+ default: !1
587
+ },
588
+ pressed: {
589
+ type: Boolean,
590
+ default: !1
591
+ },
592
+ size: { default: "md" }
593
+ },
594
+ emits: ["update:pressed"],
595
+ setup(e, { emit: t }) {
596
+ let n = t, r = D(), i = (e) => {
597
+ n("update:pressed", e);
598
+ };
599
+ return (t, n) => (y(), c(T(B), {
600
+ class: "fg-toggle-button",
601
+ "data-size": e.size,
602
+ disabled: e.disabled,
603
+ "model-value": e.pressed,
604
+ "onUpdate:modelValue": i
605
+ }, {
606
+ default: O(() => [n[0] ||= d("span", {
607
+ class: "fg-toggle-button__switch",
608
+ "aria-hidden": "true"
609
+ }, null, -1), d("span", He, [d("span", Ue, [S(t.$slots, "default")]), r.description ? (y(), u("span", We, [S(t.$slots, "description")])) : l("", !0)])]),
610
+ _: 3
611
+ }, 8, [
612
+ "data-size",
613
+ "disabled",
614
+ "model-value"
615
+ ]));
616
+ }
617
+ }), Ke = /* @__PURE__ */ m({
532
618
  __name: "UiSurface",
533
619
  props: {
534
620
  as: { default: "section" },
535
621
  padding: { default: "default" }
536
622
  },
537
623
  setup(e) {
538
- return (t, n) => (y(), c(D(M), {
624
+ return (t, n) => (y(), c(T(j), {
539
625
  as: e.as,
540
626
  class: "fg-surface",
541
627
  "data-padding": e.padding
542
628
  }, {
543
- default: k(() => [C(t.$slots, "default")]),
629
+ default: O(() => [S(t.$slots, "default")]),
544
630
  _: 3
545
631
  }, 8, ["as", "data-padding"]));
546
632
  }
547
633
  });
548
634
  //#endregion
549
- export { de as UiAlert, fe as UiBadge, r as UiButton, K as UiCard, he as UiCheckbox, ue as UiCodeBlock, t as UiDialog, i as UiDrawer, be as UiField, $ as UiInput, Se as UiProgress, we as UiRadioCard, Te as UiRadioCardGroup, Ee as UiSelect, De as UiSlider, Oe as UiSurface, n as UiTabs, a as useActiveSection };
635
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filipgutica/ui",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
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 {
8
+ .fg-dialog__content, .fg-code-block, .fg-toggle-button {
9
9
  font-family: var(--font-ui);
10
10
  font-size: var(--text-md);
11
11
  font-weight: var(--weight-regular);
@@ -51,7 +51,7 @@
51
51
  }
52
52
  .fg-code-block__copy:hover { background: color-mix(in srgb, currentColor 12%, transparent); }
53
53
  .fg-code-block__copy svg { width: 1rem; height: 1rem; }
54
- .fg-code-block__copy:focus-visible, .fg-code-block__pre:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
54
+ .fg-code-block__copy:focus-visible, .fg-code-block__pre:focus-visible, .fg-figure__plate:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
55
55
  .fg-code-block__pre { margin: 0; padding: 1rem; overflow: auto; max-height: 32rem; tab-size: 2; }
56
56
  .fg-code-block__pre, .fg-code-block__pre code { font-family: var(--font-mono); font-size: 0.8125rem; line-height: 1.65; }
57
57
  .fg-code-block__pre code { display: block; color: inherit; }
@@ -141,7 +141,8 @@
141
141
  .fg-button:disabled,
142
142
  .fg-input:disabled,
143
143
  .fg-select:disabled,
144
- .fg-checkbox[data-disabled="true"] {
144
+ .fg-checkbox[data-disabled="true"],
145
+ .fg-toggle-button:disabled {
145
146
  cursor: not-allowed;
146
147
  opacity: 0.58;
147
148
  }
@@ -602,6 +603,128 @@
602
603
  font-size: var(--text-sm);
603
604
  }
604
605
 
606
+ .fg-figure {
607
+ display: grid;
608
+ grid-template-columns: minmax(0, 1fr);
609
+ gap: var(--space-3);
610
+ min-width: 0;
611
+ margin: 0;
612
+ }
613
+
614
+ /* Wide content scrolls inside the plate so the page never overflows. */
615
+ .fg-figure__plate {
616
+ min-width: 0;
617
+ overflow-x: auto;
618
+ padding: var(--space-5);
619
+ border: 1px solid var(--color-border-subtle);
620
+ border-radius: var(--radius-panel);
621
+ background: var(--color-surface);
622
+ }
623
+
624
+ .fg-figure__caption {
625
+ max-width: var(--measure);
626
+ color: var(--color-muted);
627
+ font-family: var(--font-ui);
628
+ font-size: var(--text-sm);
629
+ line-height: var(--leading);
630
+ }
631
+
632
+ .fg-figure__number {
633
+ color: var(--color-text);
634
+ font-weight: var(--weight-medium);
635
+ }
636
+
637
+ @media (max-width: 680px) {
638
+ .fg-figure__plate { padding: var(--space-4); }
639
+ }
640
+
641
+ .fg-score {
642
+ display: inline-flex;
643
+ align-items: center;
644
+ gap: var(--space-2);
645
+ font-variant-numeric: tabular-nums;
646
+ white-space: nowrap;
647
+ }
648
+
649
+ .fg-score__pips { display: inline-flex; gap: 0.1875rem; }
650
+
651
+ .fg-score__pip {
652
+ width: 0.5rem;
653
+ height: 0.5rem;
654
+ border: 1px solid var(--color-border);
655
+ border-radius: var(--radius-pill);
656
+ }
657
+
658
+ .fg-score__pip[data-filled="true"] {
659
+ border-color: var(--color-accent);
660
+ background: var(--color-accent);
661
+ }
662
+
663
+ .fg-score__value { font-weight: var(--weight-medium); }
664
+ .fg-score__max { color: var(--color-muted); font-weight: var(--weight-regular); }
665
+
666
+ .fg-toggle-button {
667
+ display: flex;
668
+ align-items: center;
669
+ gap: var(--space-3);
670
+ padding: var(--space-2) var(--space-3);
671
+ border: 1px solid var(--color-border-subtle);
672
+ border-radius: var(--radius-control);
673
+ color: var(--color-text);
674
+ background: var(--color-surface-raised);
675
+ line-height: var(--leading-tight);
676
+ text-align: left;
677
+ cursor: pointer;
678
+ }
679
+
680
+ .fg-toggle-button[data-size="sm"] { min-height: var(--control-sm); font-size: var(--text-sm); }
681
+ .fg-toggle-button[data-size="md"] { min-height: var(--control-md); font-size: var(--text-md); }
682
+ .fg-toggle-button[data-size="lg"] { min-height: var(--control-lg); font-size: var(--text-lg); }
683
+
684
+ .fg-toggle-button:hover:not(:disabled, [aria-pressed="true"]) { border-color: var(--color-border); }
685
+ .fg-toggle-button[aria-pressed="true"] { border-color: var(--color-accent); }
686
+
687
+ /* The thumb's position, not only its color, shows the state. */
688
+ .fg-toggle-button__switch {
689
+ position: relative;
690
+ flex: none;
691
+ width: 1.75rem;
692
+ height: 1rem;
693
+ border: 1px solid var(--color-border);
694
+ border-radius: var(--radius-pill);
695
+ background: var(--color-surface-muted);
696
+ transition: background-color var(--duration) var(--ease-out), border-color var(--duration) var(--ease-out);
697
+ }
698
+
699
+ .fg-toggle-button__switch::after {
700
+ position: absolute;
701
+ top: 0.125rem;
702
+ left: 0.125rem;
703
+ width: 0.625rem;
704
+ height: 0.625rem;
705
+ border-radius: var(--radius-pill);
706
+ background: var(--color-border);
707
+ content: "";
708
+ transition: transform var(--duration) var(--ease-out), background-color var(--duration) var(--ease-out);
709
+ }
710
+
711
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch {
712
+ border-color: var(--color-accent);
713
+ background: var(--color-accent);
714
+ }
715
+
716
+ .fg-toggle-button[aria-pressed="true"] .fg-toggle-button__switch::after {
717
+ background: var(--color-button-text);
718
+ transform: translateX(0.75rem);
719
+ }
720
+
721
+ .fg-toggle-button__text { display: grid; min-width: 0; }
722
+
723
+ .fg-toggle-button__description {
724
+ color: var(--color-muted);
725
+ font-size: var(--text-xs);
726
+ }
727
+
605
728
  .fg-progress {
606
729
  position: relative;
607
730
  height: 0.55rem;
@@ -745,7 +868,8 @@
745
868
  .fg-radio-card:focus-visible,
746
869
  .fg-slider__thumb:focus-visible,
747
870
  .fg-dialog__close:focus-visible,
748
- .fg-dialog__content:focus-visible {
871
+ .fg-dialog__content:focus-visible,
872
+ .fg-toggle-button:focus-visible {
749
873
  outline: 2px solid var(--color-focus);
750
874
  outline-offset: 2px;
751
875
  }
@@ -759,7 +883,8 @@
759
883
  :root.high-contrast .fg-surface,
760
884
  :root.high-contrast .fg-card,
761
885
  :root.high-contrast .fg-code-block,
762
- :root.high-contrast .fg-dialog__content {
886
+ :root.high-contrast .fg-dialog__content,
887
+ :root.high-contrast .fg-toggle-button {
763
888
  border-width: 2px;
764
889
  border-color: var(--color-border);
765
890
  }
@@ -783,7 +908,9 @@
783
908
  .fg-radio-card,
784
909
  .fg-slider__range,
785
910
  .fg-dialog__close,
786
- .fg-progress__indicator { transition: none; }
911
+ .fg-progress__indicator,
912
+ .fg-toggle-button__switch,
913
+ .fg-toggle-button__switch::after { transition: none; }
787
914
 
788
915
  .fg-button[aria-busy="true"]::before { animation-duration: 1.4s; }
789
916
  }