@oods/components-vue 0.3.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +501 -101
- package/dist/index.d.cts +376 -24
- package/dist/index.d.ts +376 -24
- package/dist/index.js +500 -104
- package/dist/ported.cjs +210 -93
- package/dist/ported.d.cts +2 -1
- package/dist/ported.d.ts +2 -1
- package/dist/ported.js +212 -95
- package/evidence/vue-readiness.v1.json +293 -1
- package/package.json +3 -3
package/dist/ported.cjs
CHANGED
|
@@ -4,6 +4,11 @@ var componentContracts = require('@oods/component-contracts');
|
|
|
4
4
|
var vue = require('vue');
|
|
5
5
|
|
|
6
6
|
// src/ported.ts
|
|
7
|
+
function statusIcon(name) {
|
|
8
|
+
return vue.h("svg", { ...componentContracts.STATUS_ICON_SVG_ATTRS }, componentContracts.STATUS_ICON_SHAPES[name].map((shape) => vue.h(shape.tag, { ...shape.attrs })));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// src/primitives.ts
|
|
7
12
|
var toneProp = String;
|
|
8
13
|
var emphasisProp = String;
|
|
9
14
|
var sizeProp = String;
|
|
@@ -144,7 +149,7 @@ vue.defineComponent({
|
|
|
144
149
|
class: "oods-banner-dismiss oods-banner__dismiss",
|
|
145
150
|
"aria-label": props.dismissLabel,
|
|
146
151
|
onClick: () => emit("dismiss")
|
|
147
|
-
}, [
|
|
152
|
+
}, [statusIcon("x")]) : null
|
|
148
153
|
]);
|
|
149
154
|
};
|
|
150
155
|
}
|
|
@@ -154,7 +159,7 @@ vue.defineComponent({
|
|
|
154
159
|
props: {
|
|
155
160
|
content: { type: [String, Number], default: "" },
|
|
156
161
|
intent: { type: String, default: "neutral" },
|
|
157
|
-
size: { type:
|
|
162
|
+
size: { type: String, default: "md" },
|
|
158
163
|
disabled: Boolean,
|
|
159
164
|
type: { type: String, default: "button" }
|
|
160
165
|
},
|
|
@@ -181,6 +186,130 @@ vue.defineComponent({
|
|
|
181
186
|
}, [slotOrValue(slots.default, props.content)]);
|
|
182
187
|
}
|
|
183
188
|
});
|
|
189
|
+
var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
|
|
190
|
+
var pageLocks = 0;
|
|
191
|
+
var pageStyle;
|
|
192
|
+
function lockPageScroll() {
|
|
193
|
+
const page = document.documentElement;
|
|
194
|
+
if (pageLocks++ === 0) {
|
|
195
|
+
const scrollbar = window.innerWidth - page.clientWidth;
|
|
196
|
+
pageStyle = { overflow: page.style.overflow, paddingRight: page.style.paddingRight };
|
|
197
|
+
if (scrollbar > 0) page.style.paddingRight = `${parseFloat(getComputedStyle(page).paddingRight) + scrollbar}px`;
|
|
198
|
+
page.style.overflow = "hidden";
|
|
199
|
+
}
|
|
200
|
+
let held = true;
|
|
201
|
+
return () => {
|
|
202
|
+
if (!held) return;
|
|
203
|
+
held = false;
|
|
204
|
+
if (--pageLocks === 0 && pageStyle) {
|
|
205
|
+
page.style.overflow = pageStyle.overflow;
|
|
206
|
+
page.style.paddingRight = pageStyle.paddingRight;
|
|
207
|
+
pageStyle = void 0;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
var outsideBox = (event, dialog) => {
|
|
212
|
+
const box = dialog.getBoundingClientRect();
|
|
213
|
+
return event.clientX < box.left || event.clientX > box.right || event.clientY < box.top || event.clientY > box.bottom;
|
|
214
|
+
};
|
|
215
|
+
vue.defineComponent({
|
|
216
|
+
name: "OodsDialog",
|
|
217
|
+
props: {
|
|
218
|
+
id: String,
|
|
219
|
+
open: Boolean,
|
|
220
|
+
modal: { type: Boolean, default: true },
|
|
221
|
+
title: { type: String, default: "" },
|
|
222
|
+
description: String,
|
|
223
|
+
dismissLabel: { type: String, default: "Close" },
|
|
224
|
+
size: { type: String, default: "md" },
|
|
225
|
+
actions: { type: [String, Number, Object, Array], default: void 0 }
|
|
226
|
+
},
|
|
227
|
+
emits: {
|
|
228
|
+
close: () => true
|
|
229
|
+
},
|
|
230
|
+
setup(props, { emit, slots }) {
|
|
231
|
+
const generatedId = vue.useId().replace(/[^\w-]/g, "");
|
|
232
|
+
const dialogId = vue.computed(() => props.id || `oods-dialog-${generatedId}`);
|
|
233
|
+
const element = vue.ref(null);
|
|
234
|
+
const mounted = vue.ref(false);
|
|
235
|
+
const managed = vue.computed(() => props.modal && mounted.value && canShowModal());
|
|
236
|
+
let unlockScroll;
|
|
237
|
+
let pressedBackdrop = false;
|
|
238
|
+
const releaseScroll = () => {
|
|
239
|
+
unlockScroll?.();
|
|
240
|
+
unlockScroll = void 0;
|
|
241
|
+
};
|
|
242
|
+
const sync = () => {
|
|
243
|
+
const dialog = element.value;
|
|
244
|
+
if (!dialog || !managed.value) return;
|
|
245
|
+
if (props.open && !dialog.open) {
|
|
246
|
+
dialog.showModal();
|
|
247
|
+
unlockScroll ??= lockPageScroll();
|
|
248
|
+
} else if (!props.open && dialog.open) dialog.close();
|
|
249
|
+
};
|
|
250
|
+
vue.onMounted(() => {
|
|
251
|
+
mounted.value = true;
|
|
252
|
+
});
|
|
253
|
+
vue.onBeforeUnmount(releaseScroll);
|
|
254
|
+
vue.watch([() => props.open, managed], sync, { flush: "post" });
|
|
255
|
+
const requestClose = (event) => {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
emit("close");
|
|
258
|
+
};
|
|
259
|
+
return () => {
|
|
260
|
+
const titleId = `${dialogId.value}-title`;
|
|
261
|
+
const descriptionId = `${dialogId.value}-description`;
|
|
262
|
+
const actions = slotOrValue(slots.actions, props.actions);
|
|
263
|
+
return vue.h("dialog", {
|
|
264
|
+
ref: element,
|
|
265
|
+
id: dialogId.value,
|
|
266
|
+
class: "oods-dialog",
|
|
267
|
+
"data-oods-component": "Dialog",
|
|
268
|
+
"data-size": props.size,
|
|
269
|
+
"aria-labelledby": titleId,
|
|
270
|
+
"aria-describedby": props.description ? descriptionId : void 0,
|
|
271
|
+
open: managed.value ? void 0 : props.open,
|
|
272
|
+
onKeydown: (event) => {
|
|
273
|
+
if (event.key === "Escape" && !event.defaultPrevented) requestClose(event);
|
|
274
|
+
},
|
|
275
|
+
onCancel: requestClose,
|
|
276
|
+
// A close event from moving a mounted dialog into the top layer finds it open again, and is not reported. Any other
|
|
277
|
+
// close releases the page; when the browser closed it (a close request it would not let be cancelled) while open is
|
|
278
|
+
// still true, it is reported.
|
|
279
|
+
onClose: () => {
|
|
280
|
+
if (element.value?.open) return;
|
|
281
|
+
releaseScroll();
|
|
282
|
+
if (props.open) emit("close");
|
|
283
|
+
},
|
|
284
|
+
onMousedown: (event) => {
|
|
285
|
+
pressedBackdrop = managed.value && event.target === event.currentTarget && outsideBox(event, event.currentTarget);
|
|
286
|
+
},
|
|
287
|
+
// s223-m02 (#2527 ruling 13b): a click on the backdrop emits close, as the close control does. A press that began
|
|
288
|
+
// inside the dialog (text selected and dragged out) is not a backdrop click.
|
|
289
|
+
onClick: (event) => {
|
|
290
|
+
const backdrop = pressedBackdrop && event.target === event.currentTarget && outsideBox(event, event.currentTarget);
|
|
291
|
+
pressedBackdrop = false;
|
|
292
|
+
if (backdrop) emit("close");
|
|
293
|
+
}
|
|
294
|
+
}, [
|
|
295
|
+
vue.h("div", { class: "oods-dialog__header" }, [
|
|
296
|
+
vue.h("div", { class: "oods-dialog__heading" }, [
|
|
297
|
+
vue.h("h2", { id: titleId, class: "oods-dialog__title" }, props.title),
|
|
298
|
+
props.description ? vue.h("p", { id: descriptionId, class: "oods-dialog__description" }, props.description) : null
|
|
299
|
+
]),
|
|
300
|
+
vue.h("button", {
|
|
301
|
+
type: "button",
|
|
302
|
+
class: "oods-dialog__close",
|
|
303
|
+
"aria-label": props.dismissLabel,
|
|
304
|
+
onClick: () => emit("close")
|
|
305
|
+
}, [statusIcon("x")])
|
|
306
|
+
]),
|
|
307
|
+
slots.default ? vue.h("div", { class: "oods-dialog__body" }, slots.default()) : null,
|
|
308
|
+
actions !== void 0 && actions !== null && actions !== "" ? vue.h("div", { class: "oods-dialog__footer" }, [actions]) : null
|
|
309
|
+
]);
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
});
|
|
184
313
|
var SAFE_CARD_ELEMENTS = /* @__PURE__ */ new Set(["div", "article", "section", "aside"]);
|
|
185
314
|
vue.defineComponent({
|
|
186
315
|
name: "OodsCard",
|
|
@@ -575,82 +704,75 @@ vue.defineComponent({
|
|
|
575
704
|
};
|
|
576
705
|
}
|
|
577
706
|
});
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
},
|
|
592
|
-
active: {
|
|
593
|
-
description: "Subscription is paid and service is provisioned.",
|
|
594
|
-
tone: "success",
|
|
595
|
-
icon: "\u2714\uFE0E"
|
|
596
|
-
},
|
|
597
|
-
paused: {
|
|
598
|
-
description: "Billing paused temporarily by finance or customer request.",
|
|
599
|
-
tone: "neutral",
|
|
600
|
-
icon: "\u23F8"
|
|
601
|
-
},
|
|
602
|
-
pending_cancellation: {
|
|
603
|
-
description: "Subscription will cancel at period end but remains active now.",
|
|
604
|
-
tone: "info",
|
|
605
|
-
icon: "\u2026"
|
|
606
|
-
},
|
|
607
|
-
past_due: {
|
|
608
|
-
description: "Renewal payment failed; smart retries ongoing and access retained during the grace window.",
|
|
609
|
-
tone: "critical",
|
|
610
|
-
icon: "\u26A0\uFE0E"
|
|
611
|
-
},
|
|
612
|
-
unpaid: {
|
|
613
|
-
description: "Payment retries exhausted; service access revoked.",
|
|
614
|
-
tone: "critical",
|
|
615
|
-
icon: "\u2A2F"
|
|
616
|
-
},
|
|
617
|
-
terminated: {
|
|
618
|
-
description: "Subscription ended; service access revoked and billing stopped.",
|
|
619
|
-
tone: "neutral",
|
|
620
|
-
icon: "\u2205"
|
|
621
|
-
}
|
|
707
|
+
vue.defineComponent({
|
|
708
|
+
name: "OodsSwitch",
|
|
709
|
+
props: {
|
|
710
|
+
id: String,
|
|
711
|
+
label: String,
|
|
712
|
+
modelValue: { type: Boolean, default: void 0 },
|
|
713
|
+
checked: { type: Boolean, default: void 0 },
|
|
714
|
+
defaultChecked: Boolean,
|
|
715
|
+
required: Boolean,
|
|
716
|
+
disabled: Boolean,
|
|
717
|
+
help: String,
|
|
718
|
+
validation: Object,
|
|
719
|
+
size: { type: String, default: "md" }
|
|
622
720
|
},
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
721
|
+
emits: {
|
|
722
|
+
"update:modelValue": (_value) => true,
|
|
723
|
+
change: (_value) => true
|
|
724
|
+
},
|
|
725
|
+
setup(props, { emit, slots }) {
|
|
726
|
+
const internalChecked = vue.ref(props.defaultChecked);
|
|
727
|
+
const currentChecked = vue.computed(() => props.modelValue ?? props.checked ?? internalChecked.value);
|
|
728
|
+
const metadata = useFieldMetadata("Switch", props, slots);
|
|
729
|
+
const toggle = () => {
|
|
730
|
+
const next = !currentChecked.value;
|
|
731
|
+
if (props.modelValue === void 0 && props.checked === void 0) internalChecked.value = next;
|
|
732
|
+
emit("update:modelValue", next);
|
|
733
|
+
emit("change", next);
|
|
734
|
+
};
|
|
735
|
+
return () => {
|
|
736
|
+
const label = slots.label?.() ?? props.label;
|
|
737
|
+
const help = slots.help?.() ?? props.help;
|
|
738
|
+
const validation = slots.validation?.() ?? props.validation?.message;
|
|
739
|
+
const controlId = metadata.controlId.value;
|
|
740
|
+
return vue.h("div", {
|
|
741
|
+
class: "oods-field oods-switch",
|
|
742
|
+
style: validationStyle(props.validation),
|
|
743
|
+
"data-oods-component": "Switch",
|
|
744
|
+
"data-size": props.size,
|
|
745
|
+
"data-validation-state": props.validation?.state
|
|
746
|
+
}, [
|
|
747
|
+
vue.h("div", { class: "oods-switch__row" }, [
|
|
748
|
+
vue.h("button", {
|
|
749
|
+
id: controlId,
|
|
750
|
+
type: "button",
|
|
751
|
+
role: "switch",
|
|
752
|
+
class: "oods-switch__control",
|
|
753
|
+
"aria-checked": currentChecked.value ? "true" : "false",
|
|
754
|
+
"aria-labelledby": `${controlId}-label`,
|
|
755
|
+
"aria-describedby": metadata.describedBy.value,
|
|
756
|
+
"aria-required": props.required ? "true" : void 0,
|
|
757
|
+
"aria-invalid": props.validation?.state === "error" ? "true" : void 0,
|
|
758
|
+
disabled: props.disabled,
|
|
759
|
+
onClick: toggle
|
|
760
|
+
}, [vue.h("span", { class: "oods-switch__thumb", "aria-hidden": "true" })]),
|
|
761
|
+
vue.h("label", { id: `${controlId}-label`, class: "oods-field-label oods-switch__label", for: controlId }, [
|
|
762
|
+
label,
|
|
763
|
+
props.required ? vue.h("span", { class: "oods-field-required", "aria-hidden": "true" }, "*") : null
|
|
764
|
+
])
|
|
765
|
+
]),
|
|
766
|
+
help ? vue.h("p", { id: metadata.helpId.value, class: "oods-field-help" }, help) : null,
|
|
767
|
+
validation ? vue.h("p", {
|
|
768
|
+
id: metadata.validationId.value,
|
|
769
|
+
class: "oods-field-error",
|
|
770
|
+
role: props.validation?.state === "error" ? "alert" : void 0
|
|
771
|
+
}, validation) : null
|
|
772
|
+
]);
|
|
773
|
+
};
|
|
649
774
|
}
|
|
650
|
-
};
|
|
651
|
-
var STATUS_ALIASES = {
|
|
652
|
-
subscription: { delinquent: "unpaid" }
|
|
653
|
-
};
|
|
775
|
+
});
|
|
654
776
|
function isRecord(value) {
|
|
655
777
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
656
778
|
}
|
|
@@ -667,18 +789,13 @@ function statusLabel2(status) {
|
|
|
667
789
|
return status.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
|
|
668
790
|
}
|
|
669
791
|
function getPortedStatusPresentation(domain, status) {
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
description: "Status not found in registry; falling back to the requested token set.",
|
|
678
|
-
tone: "neutral"
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
return { ...metadata, label: statusLabel2(status) };
|
|
792
|
+
const presentation = componentContracts.getStatusPresentation(domain.toLowerCase(), status);
|
|
793
|
+
return {
|
|
794
|
+
label: statusLabel2(status || "Unknown"),
|
|
795
|
+
description: presentation.description,
|
|
796
|
+
tone: presentation.tone,
|
|
797
|
+
icon: componentContracts.resolveStatusIcon(presentation.iconName)
|
|
798
|
+
};
|
|
682
799
|
}
|
|
683
800
|
function formatPrice(amountCents, amount, currency) {
|
|
684
801
|
const normalizedAmount = amount;
|
|
@@ -822,11 +939,10 @@ var StatusBadge = vue.defineComponent({
|
|
|
822
939
|
domain: props.domain,
|
|
823
940
|
tone,
|
|
824
941
|
emphasis: props.variant === "solid" ? "solid" : props.emphasis,
|
|
825
|
-
icon: props.showIcon ? presentation.icon : void 0,
|
|
826
942
|
title: stringValue(attrs.title) ?? presentation.description,
|
|
827
943
|
"aria-label": ariaLabel,
|
|
828
944
|
"data-oods-component": "StatusBadge"
|
|
829
|
-
}, slots);
|
|
945
|
+
}, props.showIcon && presentation.icon && !slots.icon ? { ...slots, icon: () => statusIcon(presentation.icon) } : slots);
|
|
830
946
|
};
|
|
831
947
|
}
|
|
832
948
|
});
|
|
@@ -1139,7 +1255,7 @@ var SearchInput = vue.defineComponent({
|
|
|
1139
1255
|
"aria-label": "Clear search",
|
|
1140
1256
|
disabled: props.disabled,
|
|
1141
1257
|
onClick: clear
|
|
1142
|
-
}, "
|
|
1258
|
+
}, [statusIcon("x")]) : null
|
|
1143
1259
|
]);
|
|
1144
1260
|
};
|
|
1145
1261
|
}
|
|
@@ -1286,17 +1402,18 @@ var RelativeTimestamp = vue.defineComponent({
|
|
|
1286
1402
|
props.createdAt
|
|
1287
1403
|
) ?? "";
|
|
1288
1404
|
if (props.hideWhenEmpty && (!datetime || Number.isNaN(Date.parse(datetime)))) return null;
|
|
1405
|
+
const absolute = componentContracts.formatDateTime(datetime, { timeZone: props.timezone });
|
|
1289
1406
|
const content = firstDefined(
|
|
1290
1407
|
props.relative,
|
|
1291
1408
|
props.label,
|
|
1292
1409
|
props.text,
|
|
1293
|
-
props.now === void 0 ?
|
|
1410
|
+
!absolute ? "Unknown time" : props.now === void 0 ? absolute : relativeTimestampLabel(datetime, props.now)
|
|
1294
1411
|
) ?? "";
|
|
1295
1412
|
return vue.h("time", {
|
|
1296
1413
|
...attrs,
|
|
1297
1414
|
class: mergedClass("oods-relative-timestamp", attrs.class),
|
|
1298
1415
|
datetime: datetime || void 0,
|
|
1299
|
-
title: stringValue(attrs.title) ??
|
|
1416
|
+
title: stringValue(attrs.title) ?? absolute,
|
|
1300
1417
|
"data-oods-component": "RelativeTimestamp"
|
|
1301
1418
|
}, content);
|
|
1302
1419
|
};
|
package/dist/ported.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as vue from 'vue';
|
|
2
2
|
import { PropType, VNode } from 'vue';
|
|
3
|
+
import { StatusIconName } from '@oods/component-contracts';
|
|
3
4
|
|
|
4
5
|
type ComponentTone = 'neutral' | 'info' | 'accent' | 'positive' | 'success' | 'warning' | 'critical' | 'danger';
|
|
5
6
|
type ComponentEmphasis = 'subtle' | 'solid';
|
|
@@ -21,7 +22,7 @@ type PaginationItem = {
|
|
|
21
22
|
type StatusMetadata = {
|
|
22
23
|
description: string;
|
|
23
24
|
tone: ComponentTone;
|
|
24
|
-
icon?:
|
|
25
|
+
icon?: StatusIconName;
|
|
25
26
|
};
|
|
26
27
|
type StatusPresentation = StatusMetadata & {
|
|
27
28
|
label: string;
|
package/dist/ported.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as vue from 'vue';
|
|
2
2
|
import { PropType, VNode } from 'vue';
|
|
3
|
+
import { StatusIconName } from '@oods/component-contracts';
|
|
3
4
|
|
|
4
5
|
type ComponentTone = 'neutral' | 'info' | 'accent' | 'positive' | 'success' | 'warning' | 'critical' | 'danger';
|
|
5
6
|
type ComponentEmphasis = 'subtle' | 'solid';
|
|
@@ -21,7 +22,7 @@ type PaginationItem = {
|
|
|
21
22
|
type StatusMetadata = {
|
|
22
23
|
description: string;
|
|
23
24
|
tone: ComponentTone;
|
|
24
|
-
icon?:
|
|
25
|
+
icon?: StatusIconName;
|
|
25
26
|
};
|
|
26
27
|
type StatusPresentation = StatusMetadata & {
|
|
27
28
|
label: string;
|