@oods/components-vue 0.3.3 → 0.4.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.
- package/README.md +1 -1
- package/dist/index.cjs +184 -100
- package/dist/index.d.cts +229 -14
- package/dist/index.d.ts +229 -14
- package/dist/index.js +185 -103
- package/dist/ported.cjs +163 -93
- package/dist/ported.d.cts +2 -1
- package/dist/ported.d.ts +2 -1
- package/dist/ported.js +165 -95
- package/evidence/vue-readiness.v1.json +147 -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,83 @@ 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
|
+
vue.defineComponent({
|
|
191
|
+
name: "OodsDialog",
|
|
192
|
+
props: {
|
|
193
|
+
id: String,
|
|
194
|
+
open: Boolean,
|
|
195
|
+
modal: { type: Boolean, default: true },
|
|
196
|
+
title: { type: String, default: "" },
|
|
197
|
+
description: String,
|
|
198
|
+
dismissLabel: { type: String, default: "Close" },
|
|
199
|
+
size: { type: String, default: "md" },
|
|
200
|
+
actions: { type: [String, Number, Object, Array], default: void 0 }
|
|
201
|
+
},
|
|
202
|
+
emits: {
|
|
203
|
+
close: () => true
|
|
204
|
+
},
|
|
205
|
+
setup(props, { emit, slots }) {
|
|
206
|
+
const generatedId = vue.useId().replace(/[^\w-]/g, "");
|
|
207
|
+
const dialogId = vue.computed(() => props.id || `oods-dialog-${generatedId}`);
|
|
208
|
+
const element = vue.ref(null);
|
|
209
|
+
const mounted = vue.ref(false);
|
|
210
|
+
const managed = vue.computed(() => props.modal && mounted.value && canShowModal());
|
|
211
|
+
const sync = () => {
|
|
212
|
+
const dialog = element.value;
|
|
213
|
+
if (!dialog || !managed.value) return;
|
|
214
|
+
if (props.open && !dialog.open) dialog.showModal();
|
|
215
|
+
else if (!props.open && dialog.open) dialog.close();
|
|
216
|
+
};
|
|
217
|
+
vue.onMounted(() => {
|
|
218
|
+
mounted.value = true;
|
|
219
|
+
});
|
|
220
|
+
vue.watch([() => props.open, managed], sync, { flush: "post" });
|
|
221
|
+
const requestClose = (event) => {
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
emit("close");
|
|
224
|
+
};
|
|
225
|
+
return () => {
|
|
226
|
+
const titleId = `${dialogId.value}-title`;
|
|
227
|
+
const descriptionId = `${dialogId.value}-description`;
|
|
228
|
+
const actions = slotOrValue(slots.actions, props.actions);
|
|
229
|
+
return vue.h("dialog", {
|
|
230
|
+
ref: element,
|
|
231
|
+
id: dialogId.value,
|
|
232
|
+
class: "oods-dialog",
|
|
233
|
+
"data-oods-component": "Dialog",
|
|
234
|
+
"data-size": props.size,
|
|
235
|
+
"aria-labelledby": titleId,
|
|
236
|
+
"aria-describedby": props.description ? descriptionId : void 0,
|
|
237
|
+
open: managed.value ? void 0 : props.open,
|
|
238
|
+
onKeydown: (event) => {
|
|
239
|
+
if (event.key === "Escape" && !event.defaultPrevented) requestClose(event);
|
|
240
|
+
},
|
|
241
|
+
onCancel: requestClose,
|
|
242
|
+
// The browser closed it (a close request it would not let be cancelled) while open is still true. A close event
|
|
243
|
+
// from moving a mounted dialog into the top layer finds it open again, and is not reported.
|
|
244
|
+
onClose: () => {
|
|
245
|
+
if (props.open && !element.value?.open) emit("close");
|
|
246
|
+
}
|
|
247
|
+
}, [
|
|
248
|
+
vue.h("div", { class: "oods-dialog__header" }, [
|
|
249
|
+
vue.h("div", { class: "oods-dialog__heading" }, [
|
|
250
|
+
vue.h("h2", { id: titleId, class: "oods-dialog__title" }, props.title),
|
|
251
|
+
props.description ? vue.h("p", { id: descriptionId, class: "oods-dialog__description" }, props.description) : null
|
|
252
|
+
]),
|
|
253
|
+
vue.h("button", {
|
|
254
|
+
type: "button",
|
|
255
|
+
class: "oods-dialog__close",
|
|
256
|
+
"aria-label": props.dismissLabel,
|
|
257
|
+
onClick: () => emit("close")
|
|
258
|
+
}, [statusIcon("x")])
|
|
259
|
+
]),
|
|
260
|
+
slots.default ? vue.h("div", { class: "oods-dialog__body" }, slots.default()) : null,
|
|
261
|
+
actions !== void 0 && actions !== null && actions !== "" ? vue.h("div", { class: "oods-dialog__footer" }, [actions]) : null
|
|
262
|
+
]);
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
});
|
|
184
266
|
var SAFE_CARD_ELEMENTS = /* @__PURE__ */ new Set(["div", "article", "section", "aside"]);
|
|
185
267
|
vue.defineComponent({
|
|
186
268
|
name: "OodsCard",
|
|
@@ -575,82 +657,75 @@ vue.defineComponent({
|
|
|
575
657
|
};
|
|
576
658
|
}
|
|
577
659
|
});
|
|
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
|
-
}
|
|
660
|
+
vue.defineComponent({
|
|
661
|
+
name: "OodsSwitch",
|
|
662
|
+
props: {
|
|
663
|
+
id: String,
|
|
664
|
+
label: String,
|
|
665
|
+
modelValue: { type: Boolean, default: void 0 },
|
|
666
|
+
checked: { type: Boolean, default: void 0 },
|
|
667
|
+
defaultChecked: Boolean,
|
|
668
|
+
required: Boolean,
|
|
669
|
+
disabled: Boolean,
|
|
670
|
+
help: String,
|
|
671
|
+
validation: Object,
|
|
672
|
+
size: { type: String, default: "md" }
|
|
622
673
|
},
|
|
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
|
-
|
|
674
|
+
emits: {
|
|
675
|
+
"update:modelValue": (_value) => true,
|
|
676
|
+
change: (_value) => true
|
|
677
|
+
},
|
|
678
|
+
setup(props, { emit, slots }) {
|
|
679
|
+
const internalChecked = vue.ref(props.defaultChecked);
|
|
680
|
+
const currentChecked = vue.computed(() => props.modelValue ?? props.checked ?? internalChecked.value);
|
|
681
|
+
const metadata = useFieldMetadata("Switch", props, slots);
|
|
682
|
+
const toggle = () => {
|
|
683
|
+
const next = !currentChecked.value;
|
|
684
|
+
if (props.modelValue === void 0 && props.checked === void 0) internalChecked.value = next;
|
|
685
|
+
emit("update:modelValue", next);
|
|
686
|
+
emit("change", next);
|
|
687
|
+
};
|
|
688
|
+
return () => {
|
|
689
|
+
const label = slots.label?.() ?? props.label;
|
|
690
|
+
const help = slots.help?.() ?? props.help;
|
|
691
|
+
const validation = slots.validation?.() ?? props.validation?.message;
|
|
692
|
+
const controlId = metadata.controlId.value;
|
|
693
|
+
return vue.h("div", {
|
|
694
|
+
class: "oods-field oods-switch",
|
|
695
|
+
style: validationStyle(props.validation),
|
|
696
|
+
"data-oods-component": "Switch",
|
|
697
|
+
"data-size": props.size,
|
|
698
|
+
"data-validation-state": props.validation?.state
|
|
699
|
+
}, [
|
|
700
|
+
vue.h("div", { class: "oods-switch__row" }, [
|
|
701
|
+
vue.h("button", {
|
|
702
|
+
id: controlId,
|
|
703
|
+
type: "button",
|
|
704
|
+
role: "switch",
|
|
705
|
+
class: "oods-switch__control",
|
|
706
|
+
"aria-checked": currentChecked.value ? "true" : "false",
|
|
707
|
+
"aria-labelledby": `${controlId}-label`,
|
|
708
|
+
"aria-describedby": metadata.describedBy.value,
|
|
709
|
+
"aria-required": props.required ? "true" : void 0,
|
|
710
|
+
"aria-invalid": props.validation?.state === "error" ? "true" : void 0,
|
|
711
|
+
disabled: props.disabled,
|
|
712
|
+
onClick: toggle
|
|
713
|
+
}, [vue.h("span", { class: "oods-switch__thumb", "aria-hidden": "true" })]),
|
|
714
|
+
vue.h("label", { id: `${controlId}-label`, class: "oods-field-label oods-switch__label", for: controlId }, [
|
|
715
|
+
label,
|
|
716
|
+
props.required ? vue.h("span", { class: "oods-field-required", "aria-hidden": "true" }, "*") : null
|
|
717
|
+
])
|
|
718
|
+
]),
|
|
719
|
+
help ? vue.h("p", { id: metadata.helpId.value, class: "oods-field-help" }, help) : null,
|
|
720
|
+
validation ? vue.h("p", {
|
|
721
|
+
id: metadata.validationId.value,
|
|
722
|
+
class: "oods-field-error",
|
|
723
|
+
role: props.validation?.state === "error" ? "alert" : void 0
|
|
724
|
+
}, validation) : null
|
|
725
|
+
]);
|
|
726
|
+
};
|
|
649
727
|
}
|
|
650
|
-
};
|
|
651
|
-
var STATUS_ALIASES = {
|
|
652
|
-
subscription: { delinquent: "unpaid" }
|
|
653
|
-
};
|
|
728
|
+
});
|
|
654
729
|
function isRecord(value) {
|
|
655
730
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
656
731
|
}
|
|
@@ -667,18 +742,13 @@ function statusLabel2(status) {
|
|
|
667
742
|
return status.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
|
|
668
743
|
}
|
|
669
744
|
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) };
|
|
745
|
+
const presentation = componentContracts.getStatusPresentation(domain.toLowerCase(), status);
|
|
746
|
+
return {
|
|
747
|
+
label: statusLabel2(status || "Unknown"),
|
|
748
|
+
description: presentation.description,
|
|
749
|
+
tone: presentation.tone,
|
|
750
|
+
icon: componentContracts.resolveStatusIcon(presentation.iconName)
|
|
751
|
+
};
|
|
682
752
|
}
|
|
683
753
|
function formatPrice(amountCents, amount, currency) {
|
|
684
754
|
const normalizedAmount = amount;
|
|
@@ -822,11 +892,10 @@ var StatusBadge = vue.defineComponent({
|
|
|
822
892
|
domain: props.domain,
|
|
823
893
|
tone,
|
|
824
894
|
emphasis: props.variant === "solid" ? "solid" : props.emphasis,
|
|
825
|
-
icon: props.showIcon ? presentation.icon : void 0,
|
|
826
895
|
title: stringValue(attrs.title) ?? presentation.description,
|
|
827
896
|
"aria-label": ariaLabel,
|
|
828
897
|
"data-oods-component": "StatusBadge"
|
|
829
|
-
}, slots);
|
|
898
|
+
}, props.showIcon && presentation.icon && !slots.icon ? { ...slots, icon: () => statusIcon(presentation.icon) } : slots);
|
|
830
899
|
};
|
|
831
900
|
}
|
|
832
901
|
});
|
|
@@ -1139,7 +1208,7 @@ var SearchInput = vue.defineComponent({
|
|
|
1139
1208
|
"aria-label": "Clear search",
|
|
1140
1209
|
disabled: props.disabled,
|
|
1141
1210
|
onClick: clear
|
|
1142
|
-
}, "
|
|
1211
|
+
}, [statusIcon("x")]) : null
|
|
1143
1212
|
]);
|
|
1144
1213
|
};
|
|
1145
1214
|
}
|
|
@@ -1286,17 +1355,18 @@ var RelativeTimestamp = vue.defineComponent({
|
|
|
1286
1355
|
props.createdAt
|
|
1287
1356
|
) ?? "";
|
|
1288
1357
|
if (props.hideWhenEmpty && (!datetime || Number.isNaN(Date.parse(datetime)))) return null;
|
|
1358
|
+
const absolute = componentContracts.formatDateTime(datetime, { timeZone: props.timezone });
|
|
1289
1359
|
const content = firstDefined(
|
|
1290
1360
|
props.relative,
|
|
1291
1361
|
props.label,
|
|
1292
1362
|
props.text,
|
|
1293
|
-
props.now === void 0 ?
|
|
1363
|
+
!absolute ? "Unknown time" : props.now === void 0 ? absolute : relativeTimestampLabel(datetime, props.now)
|
|
1294
1364
|
) ?? "";
|
|
1295
1365
|
return vue.h("time", {
|
|
1296
1366
|
...attrs,
|
|
1297
1367
|
class: mergedClass("oods-relative-timestamp", attrs.class),
|
|
1298
1368
|
datetime: datetime || void 0,
|
|
1299
|
-
title: stringValue(attrs.title) ??
|
|
1369
|
+
title: stringValue(attrs.title) ?? absolute,
|
|
1300
1370
|
"data-oods-component": "RelativeTimestamp"
|
|
1301
1371
|
}, content);
|
|
1302
1372
|
};
|
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;
|