UNPKG

@wikimedia/codex

Version:

Codex Design System for Wikimedia

1,545 lines 450 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { ref, onMounted, defineComponent, computed, createElementBlock, openBlock, normalizeClass, createCommentVNode, toDisplayString, Comment, warn, watch, withKeys, withModifiers, renderSlot, toRef, resolveComponent, createElementVNode, createBlock, resolveDynamicComponent, withCtx, createVNode, Fragment, renderList, createTextVNode, Transition, normalizeStyle, inject, mergeProps, useId, withDirectives, vModelCheckbox, createSlots, unref, shallowRef, getCurrentScope, onScopeDispose, shallowReadonly, resolveDirective, nextTick, vModelDynamic, onUnmounted, Teleport, toHandlers, vShow, onBeforeUnmount, provide, useCssVars, toRefs, reactive, vModelRadio, vModelText, getCurrentInstance } from "vue"; function regExpEscape(value) { return value.replace(/([\\{}()|.?*+\-^$[\]])/g, "\\$1"); } const COMBINING_MARK = "[̀-ͯ҃-҉֑-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪾ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿⃐-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯-꙲ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯]"; function splitStringAtMatch(query, title) { if (!query) { return [title, "", ""]; } const sanitizedQuery = regExpEscape(query); const match = new RegExp( // Per https://www.regular-expressions.info/unicode.html, "any code point that is not a // combining mark can be followed by any number of combining marks." See also the // discussion in https://phabricator.wikimedia.org/T35242. sanitizedQuery + COMBINING_MARK + "*", "i" ).exec(title); if (!match || match.index === void 0) { return [title, "", ""]; } const matchStartIndex = match.index; const matchEndIndex = matchStartIndex + match[0].length; const highlightedTitle = title.slice(matchStartIndex, matchEndIndex); const beforeHighlight = title.slice(0, matchStartIndex); const afterHighlight = title.slice(matchEndIndex, title.length); return [beforeHighlight, highlightedTitle, afterHighlight]; } const stringHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, regExpEscape, splitStringAtMatch }, Symbol.toStringTag, { value: "Module" })); const m = '<path d="M19.765 16.059 18 19H2L.235 16.059l8-15h3.53zM9 14v2h2v-2zm0-8v6h2V6z"/>', B = '<path d="M18 19H2V1h16zM4 17h11.586l-3.922-3.922a3.5 3.5 0 111.414-1.414L16 14.586V3H4zm6-8.5a1.5 1.5 0 100 3 1.5 1.5 0 000-3"/>', V1 = '<path d="M18.154 3.837 8.034 16.62l-1.384.18-4.8-3.6 1.2-1.6 4.02 3.015 9.517-12.02z"/>', p1 = '<path d="M14.243 7.172 11.413 10l2.828 2.83-1.414 1.413L10 11.415l-2.827 2.827-1.414-1.414L8.585 10 5.757 7.172l1.415-1.414 2.827 2.828 2.83-2.828z"/><path d="M10 1a9 9 0 110 18 9 9 0 010-18m0 2a7 7 0 100 14 7 7 0 000-14"/>', i1 = '<path d="M16.707 4.707 11.414 10l5.293 5.293-1.414 1.414L10 11.414l-5.293 5.293-1.414-1.414L8.586 10 3.293 4.707l1.414-1.414L10 8.586l5.293-5.293z"/>', S1 = '<path d="M14 7H6v2.5l4 3.5 4-3.5z"/>', R1 = '<path d="M19 6.4v7.199L13.6 19H6.4L1 13.599v-7.2L6.4 1h7.2zM9 14v2h2v-2zm0-9v7h2V5z"/>', P1 = '<path d="m16.707 8.017-6 5.983H9.293l-6-5.983 1.414-1.414L10 11.896l5.293-5.293z"/>', z0 = '<path d="M15 15H5l3.5-4 2 2L15 8zM6.25 5a1.25 1.25 0 110 2.5 1.25 1.25 0 010-2.5"/><path d="M19 19H1V1h18zM3 17h14V3H3z"/>', g0 = '<path d="M19 19H1V1h18zm-8.5-6-2-2L5 15h10V8zM6.25 5a1.25 1.25 0 100 2.5 1.25 1.25 0 000-2.5"/>', M = '<path d="M13 20H7v-2h6zM10 0c1.938 0 3.58.556 4.745 1.644C15.918 2.738 16.5 4.27 16.5 6c0 2.22-1.15 3.732-2.04 4.727-.644.72-.96 1.633-.96 2.662V16h-7v-2.611c0-1.029-.317-1.942-.96-2.662C4.65 9.732 3.5 8.22 3.5 6c0-1.627.593-3.145 1.743-4.255C6.395.634 8.032 0 10 0"/>', f0 = '<path d="M10 1a9 9 0 110 18 9 9 0 010-18M8 9v2h1v2H8v2h4v-2h-1V9zm1-4v2h2V5z"/>', W2 = '<path d="M6 17H4V3h2zM16.417 4.707 11.124 10l5.293 5.293-1.414 1.414-6-6V9.293l6-6z"/>', R2 = '<path d="M16 17h-2V3h2zm-5-7.707v1.414l-5.993 6-1.414-1.414L8.886 10 3.593 4.707l1.414-1.414z"/>', Q2 = '<path d="M14 9.293v1.414l-5.982 6-1.415-1.414L11.896 10 6.603 4.707l1.414-1.414z"/>', s5 = '<path d="M13.417 4.707 8.124 10l5.293 5.293-1.414 1.414-6-6V9.293l6-6z"/>', C5 = '<path d="M8 1a7 7 0 015.605 11.191l5.102 5.102-1.414 1.414-5.102-5.102A7 7 0 118 1m0 2a5 5 0 100 10A5 5 0 008 3"/>', U5 = '<path d="M14 14.5 10 18l-4-3.5V12h8zm0-9V8H6V5.5L10 2z"/>', X5 = '<path d="M10 1a9 9 0 110 18 9 9 0 010-18M8.823 11.118 6.8 9.6l-1.2 1.6 2.8 2.1 1.381-.175 4.624-5.781-1.561-1.25z"/>', q4 = '<path d="M14 13H6v-2.5L10 7l4 3.5z"/>', v3 = m, A3 = B, J3 = V1, j3 = p1, _3 = i1, d7 = S1, m7 = R1, g7 = P1, O7 = z0, Y7 = g0, o6 = { langCodeMap: { ar: M }, default: f0 }, l8 = { ltr: W2, shouldFlip: true }, s8 = { ltr: R2, shouldFlip: true }, M8 = { ltr: Q2, shouldFlip: true }, F8 = { ltr: s5, shouldFlip: true }, G8 = C5, t9 = U5, p9 = X5, Y9 = q4; function Ih(h, l, o) { if (typeof h == "string" || "path" in h) return h; if ("shouldFlip" in h) return h.ltr; if ("rtl" in h) return o === "rtl" ? h.rtl : h.ltr; const v = l in h.langCodeMap ? h.langCodeMap[l] : h.default; return typeof v == "string" || "path" in v ? v : v.ltr; } function Ah(h, l) { if (typeof h == "string") return false; if ("langCodeMap" in h) { const o = l in h.langCodeMap ? h.langCodeMap[l] : h.default; if (typeof o == "string") return false; h = o; } if ("shouldFlipExceptions" in h && Array.isArray(h.shouldFlipExceptions)) { const o = h.shouldFlipExceptions.indexOf(l); return o === void 0 || o === -1; } return "shouldFlip" in h ? h.shouldFlip : false; } function useComputedDirection(root) { const computedDir = ref(null); onMounted(() => { const dir = window.getComputedStyle(root.value).direction; computedDir.value = dir === "ltr" || dir === "rtl" ? dir : null; }); return computedDir; } function useComputedLanguage(root) { const computedLang = ref(""); onMounted(() => { let ancestor = root.value; while ((ancestor == null ? void 0 : ancestor.lang) === "") { ancestor = ancestor.parentElement; } computedLang.value = ancestor ? ancestor == null ? void 0 : ancestor.lang : null; }); return computedLang; } function makeStringTypeValidator(allowedValues) { return (s) => typeof s === "string" && allowedValues.includes(s); } const LibraryPrefix = "cdx"; const ButtonActions = [ "default", "progressive", "destructive" ]; const ButtonWeights = [ "normal", "primary", "quiet" ]; const ButtonSizes = [ "small", "medium", "large" ]; const IconSizes = [ "x-small", "small", "medium" ]; const StatusTypes = [ "subtle", "notice", "progressive", "warning", "error", "success" ]; const statusTypeValidator = makeStringTypeValidator(StatusTypes); const TextInputTypes = [ "text", "search", "number", "email", "month", "password", "tel", "url", "week", "date", "datetime-local", "time" ]; const ValidationStatusTypes = [ "default", "warning", "error", "success" ]; const TableTextAlignments = [ "start", "center", "end", // Numbers should be aligned to the right in all reading directionalities. "number" ]; const ImageAspectRatios = [ "16:9", "3:2", "4:3", "1:1", "3:4", "2:3" ]; const imageAspectRatioValidator = makeStringTypeValidator(ImageAspectRatios); const ObjectFitOptions = [ "fill", "contain", "cover", "none", "scale-down" ]; const objectFitValidator = makeStringTypeValidator(ObjectFitOptions); const ObjectPositions = [ "top", "bottom", "left", "right", "center" ]; const imagePositionValidator = makeStringTypeValidator(ObjectPositions); const AccordionSeparations = [ "none", "minimal", "divider", "outline" ]; const DebounceInterval = 120; const PendingDelay = 500; const MenuFooterValue = "cdx-menu-footer-item"; const TabsKey = Symbol("CdxTabs"); const ActiveTabKey = Symbol("CdxActiveTab"); const AllowArbitraryKey = Symbol("CdxAllowArbitrary"); const FieldInputIdKey = Symbol("CdxFieldInputId"); const FieldDescriptionIdKey = Symbol("CdxFieldDescriptionId"); const FieldStatusKey = Symbol("CdxFieldStatus"); const DisabledKey = Symbol("CdxDisabled"); const NoInvertClass = "".concat(LibraryPrefix, "-no-invert"); const TableRowIdentifier = Symbol("CdxTableRowIdentifier"); const TablePaginationPositions = [ "top", "bottom", "both" ]; const oppositeSides = { left: "right", "left-start": "right", "left-end": "right", top: "bottom", "top-start": "bottom", "top-end": "bottom", bottom: "top", "bottom-start": "top", "bottom-end": "top", right: "left", "right-start": "left", "right-end": "left" }; const iconSizeValidator = makeStringTypeValidator(IconSizes); const _sfc_main$D = defineComponent({ name: "CdxIcon", props: { /** The SVG path or an object containing that path plus other data. */ icon: { type: [String, Object], required: true }, /** * Accessible label for the icon. If not included, the icon will be hidden from screen * readers via `aria-hidden="true"`. Browsers also display this label as a tooltip when the * user hovers over the icon. Note that this label is not rendered as visible text next * to the icon. */ iconLabel: { type: String, default: "" }, /** * Explicitly set the language code to use for the icon. See * https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/lang. * Defaults to the lang attribute of the nearest ancestor at mount time. */ lang: { type: String, default: null }, /** * Explicitly set the direction to use for the icon. See * https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dir. * Defaults to the computed direction at mount time. */ dir: { type: String, default: null }, /** * Specify icon size by choosing one of several pre-defined size * options. See the type documentation for supported size options. * The `medium` size is used by default if no size prop is provided. */ size: { type: String, default: "medium", validator: iconSizeValidator } }, setup(props) { const rootElement = ref(); const computedDir = useComputedDirection(rootElement); const computedLang = useComputedLanguage(rootElement); const overriddenDir = computed(() => { var _a; return (_a = props.dir) != null ? _a : computedDir.value; }); const overriddenLang = computed(() => { var _a; return (_a = props.lang) != null ? _a : computedLang.value; }); const rootClasses = computed(() => ({ "cdx-icon--flipped": overriddenDir.value === "rtl" && overriddenLang.value !== null && Ah(props.icon, overriddenLang.value), ["cdx-icon--".concat(props.size)]: true })); const resolvedIcon = computed( () => { var _a, _b; return Ih(props.icon, (_a = overriddenLang.value) != null ? _a : "", (_b = overriddenDir.value) != null ? _b : "ltr"); } ); const iconSvg = computed(() => typeof resolvedIcon.value === "string" ? resolvedIcon.value : ""); const iconPath = computed(() => typeof resolvedIcon.value !== "string" ? resolvedIcon.value.path : ""); return { rootElement, rootClasses, iconSvg, iconPath }; } }); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _hoisted_1$z = ["aria-hidden"]; const _hoisted_2$n = { key: 0 }; const _hoisted_3$f = ["innerHTML"]; const _hoisted_4$c = ["d"]; function _sfc_render$E(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock( "span", { ref: "rootElement", class: normalizeClass(["cdx-icon", _ctx.rootClasses]) }, [ (openBlock(), createElementBlock("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20", "aria-hidden": _ctx.iconLabel ? void 0 : true }, [ _ctx.iconLabel ? (openBlock(), createElementBlock( "title", _hoisted_2$n, toDisplayString(_ctx.iconLabel), 1 /* TEXT */ )) : createCommentVNode("v-if", true), _ctx.iconSvg ? (openBlock(), createElementBlock("g", { key: 1, innerHTML: _ctx.iconSvg }, null, 8, _hoisted_3$f)) : (openBlock(), createElementBlock("path", { key: 2, d: _ctx.iconPath }, null, 8, _hoisted_4$c)) ], 8, _hoisted_1$z)) ], 2 /* CLASS */ ); } const CdxIcon = /* @__PURE__ */ _export_sfc(_sfc_main$D, [["render", _sfc_render$E]]); function flattenSlotContents(slotContents) { const flattened = []; for (const node of slotContents) { if ( // HTML tag typeof node.type === "string" || // Component typeof node.type === "object" ) { flattened.push(node); } else if (node.type !== Comment) { if (typeof node.children === "string" && node.children.trim() !== "") { flattened.push(node.children); } else if (Array.isArray(node.children)) { flattened.push(...flattenSlotContents(node.children)); } } } return flattened; } function isComponentVNode(node, componentName) { if (typeof node.type === "object" && "name" in node.type) { if (componentName !== void 0) { return node.type.name === componentName; } return true; } return false; } function isTagVNode(node, tagName) { if (typeof node.type === "string") { { return node.type === tagName.toLowerCase(); } } return false; } function useSlotContents(slot) { const slotContents = typeof slot === "function" ? slot() : slot; return slotContents ? flattenSlotContents(slotContents) : []; } function useWarnOnce(shouldWarn, message) { if (shouldWarn()) { warn(message); return; } const stop = watch(shouldWarn, (newValue) => { if (newValue) { warn(message); stop(); } }); } function useIconOnlyButton(slot, attrs, componentName) { const isIconOnly = computed(() => { const slotContents = useSlotContents(slot); if (slotContents.length !== 1) { return false; } const soleNode = slotContents[0]; if (typeof soleNode === "object" && (isComponentVNode(soleNode, "CdxIcon") || isTagVNode(soleNode, "svg"))) { return true; } return false; }); useWarnOnce( () => isIconOnly.value && !attrs["aria-label"] && !attrs["aria-hidden"], "".concat(componentName, ": Icon-only buttons require one of the following attributes: aria-label or aria-hidden. See documentation at https://doc.wikimedia.org/codex/latest/components/demos/button.html#icon-only-button") ); return isIconOnly; } const buttonActionValidator = makeStringTypeValidator(ButtonActions); const buttonWeightValidator = makeStringTypeValidator(ButtonWeights); const buttonSizeValidator$1 = makeStringTypeValidator(ButtonSizes); const _sfc_main$C = defineComponent({ name: "CdxButton", props: { /** * The kind of action that will be taken on click. * * @values 'default', 'progressive', 'destructive' */ action: { type: String, default: "default", validator: buttonActionValidator }, /** * Visual prominence of Button. * * @values 'normal', 'primary', 'quiet' */ weight: { type: String, default: "normal", validator: buttonWeightValidator }, /** * Button size. * * Medium: Default for most cases. * Large: Use rarely, mainly for icon-only buttons on touchscreens. * Small: Use in tight spaces or inline with text. * Avoid on touchscreens - prefer medium for better accessibility. * * @values 'small', 'medium', 'large' */ size: { type: String, default: "medium", validator: buttonSizeValidator$1 } }, emits: ["click"], setup(props, { emit, slots, attrs }) { const button = ref(); const isIconOnly = useIconOnlyButton(slots.default, attrs, "CdxButton"); const isActive = ref(false); const rootClasses = computed(() => ({ ["cdx-button--action-".concat(props.action)]: true, ["cdx-button--weight-".concat(props.weight)]: true, ["cdx-button--size-".concat(props.size)]: true, "cdx-button--framed": props.weight !== "quiet", "cdx-button--icon-only": isIconOnly.value, "cdx-button--is-active": isActive.value })); const onClick = (event) => { emit("click", event); }; const setActive = (active) => { isActive.value = active; }; function onKeyDown() { setActive(true); } function onKeyUp() { var _a; setActive(false); (_a = button.value) == null ? void 0 : _a.click(); } return { button, rootClasses, onClick, onKeyDown, onKeyUp }; } }); function _sfc_render$D(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock( "button", { ref: "button", class: normalizeClass(["cdx-button", _ctx.rootClasses]), onKeydown: _cache[0] || (_cache[0] = withKeys(withModifiers((...args) => _ctx.onKeyDown && _ctx.onKeyDown(...args), ["prevent"]), ["space", "enter"])), onKeyup: _cache[1] || (_cache[1] = withKeys((...args) => _ctx.onKeyUp && _ctx.onKeyUp(...args), ["space", "enter"])), onClick: _cache[2] || (_cache[2] = (...args) => _ctx.onClick && _ctx.onClick(...args)) }, [ renderSlot(_ctx.$slots, "default") ], 34 /* CLASS, NEED_HYDRATION */ ); } const CdxButton = /* @__PURE__ */ _export_sfc(_sfc_main$C, [["render", _sfc_render$D]]); function useOptionalModelWrapper(internalValueRef, modelValueRef, emit, eventName) { return computed({ get: () => { var _a; return (_a = modelValueRef.value) != null ? _a : internalValueRef.value; }, set: (value) => { if (modelValueRef.value !== null) { emit(eventName || "update:modelValue", value); } else { internalValueRef.value = value; } } }); } const separationValidator = makeStringTypeValidator(AccordionSeparations); const _sfc_main$B = defineComponent({ name: "CdxAccordion", components: { CdxButton, CdxIcon }, props: { /** * This component accepts an optional v-model binding; use it if you * want to programmatically control the Accordion's open/closed state. * If this feature is not needed, you can omit `v-model` and just use * the "open" attribute if you want the component to render in the * expanded state. */ modelValue: { type: [Boolean, null], default: null }, /** * Forces the accordion to show the action icon. */ actionAlwaysVisible: { type: Boolean, default: false }, /** * Sets the visual style and sometimes size of the accordion. * * - 'none': no divider or outline, size scales with header content. * - 'minimal': no divider or outline, fixed small size. * - 'divider': divider line between mmultiple accordions, size scales with header content. * - 'outline': border around entire accordion, size scales with header content. * * @values 'none', 'minimal', 'divider', 'outline' */ separation: { type: String, default: "divider", validator: separationValidator }, /** * The icon that will be displayed on the right side of the accordion header when expanded. * */ actionIcon: { type: [String, Object], default: null }, /** * Label for the action button. If an action icon is being used, then a label for that icon * should be provided for ARIA support. */ actionButtonLabel: { type: String, default: "" }, /** * The heading level of the accordion title. * * @values 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' */ headingLevel: { type: String, default: "h3" } }, emits: [ /** * When the action button is clicked. * */ "action-button-click", /** * When the "open" state changes. Only emitted if v-model binding * is used in the parent scope. * * @param {boolean} newVal */ "update:modelValue", /** * When the Accordion is toggled open or closed. Always emitted * regardless of v-model binding. * * @param {boolean} isOpen */ "toggle" ], setup(props, { attrs, emit }) { const internalOpen = ref("open" in attrs); const computedOpen = useOptionalModelWrapper( internalOpen, toRef(props, "modelValue"), emit ); const emitActionButtonClick = () => { emit("action-button-click"); }; const onToggle = (e) => { computedOpen.value = e.newState === "open"; emit("toggle", computedOpen.value); }; const shouldShowActionButton = computed(() => { if (props.actionIcon) { if (computedOpen.value) { return true; } else if (props.actionAlwaysVisible) { return true; } else { return false; } } else { return false; } }); const rootClasses = computed(() => ({ "cdx-accordion--has-icon": shouldShowActionButton.value, ["cdx-accordion--separation-".concat(props.separation)]: true })); return { emitActionButtonClick, rootClasses, shouldShowActionButton, onToggle, computedOpen }; } }); const _hoisted_1$y = ["open"]; const _hoisted_2$m = { class: "cdx-accordion__header__title" }; const _hoisted_3$e = { class: "cdx-accordion__header__description" }; function _sfc_render$C(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_icon = resolveComponent("cdx-icon"); const _component_cdx_button = resolveComponent("cdx-button"); return openBlock(), createElementBlock("details", { class: normalizeClass(["cdx-accordion", _ctx.rootClasses]), open: _ctx.computedOpen || void 0, onToggle: _cache[1] || (_cache[1] = (...args) => _ctx.onToggle && _ctx.onToggle(...args)) }, [ createElementVNode("summary", null, [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.headingLevel), { class: "cdx-accordion__header" }, { default: withCtx(() => [ createElementVNode("span", _hoisted_2$m, [ renderSlot(_ctx.$slots, "title") ]), createElementVNode("span", _hoisted_3$e, [ renderSlot(_ctx.$slots, "description") ]) ]), _: 3 /* FORWARDED */ })), _ctx.shouldShowActionButton ? (openBlock(), createBlock(_component_cdx_button, { key: 0, class: "cdx-accordion__action", "aria-label": _ctx.actionButtonLabel, type: "button", weight: "quiet", onClick: withModifiers(_ctx.emitActionButtonClick, ["stop"]) }, { default: withCtx(() => [ createVNode(_component_cdx_icon, { icon: _ctx.actionIcon, "icon-label": _ctx.actionButtonLabel, size: "medium" }, null, 8, ["icon", "icon-label"]) ]), _: 1 /* STABLE */ }, 8, ["aria-label", "onClick"])) : createCommentVNode("v-if", true) ]), createElementVNode("div", { class: "cdx-accordion__content", onClick: _cache[0] || (_cache[0] = withModifiers(() => { }, ["stop"])) }, [ renderSlot(_ctx.$slots, "default") ]) ], 42, _hoisted_1$y); } const Accordion = /* @__PURE__ */ _export_sfc(_sfc_main$B, [["render", _sfc_render$C]]); function getButtonLabel(button) { if (button.label === void 0) { return button.value; } if (button.label === null) { return ""; } return button.label; } function useButtonGroupKeyboardNav(buttonsProp) { const rootElement = ref(); const focusedButtonIndex = ref(); const buttonRefs = ref(/* @__PURE__ */ new Map()); const currentDirection = useComputedDirection(rootElement); function assignTemplateRef(templateRef, index) { const button = templateRef; if (button) { buttonRefs.value.set(index, button); } } function onFocus(index) { focusedButtonIndex.value = index; } function onBlur() { focusedButtonIndex.value = void 0; } function focusNonDisabled(index, increment) { var _a; const newIndex = index + increment; const targetButton = buttonsProp.value[newIndex]; if (targetButton) { if (targetButton.disabled) { focusNonDisabled(newIndex, increment); } else { const buttonElement = (_a = buttonRefs.value.get(newIndex)) == null ? void 0 : _a.$el; buttonElement == null ? void 0 : buttonElement.focus(); } } } function next() { var _a; focusNonDisabled((_a = focusedButtonIndex.value) != null ? _a : -1, 1); } function prev() { var _a; focusNonDisabled((_a = focusedButtonIndex.value) != null ? _a : buttonsProp.value.length, -1); } function moveRight() { if (currentDirection.value === "rtl") { prev(); } else { next(); } } function moveLeft() { if (currentDirection.value === "rtl") { next(); } else { prev(); } } function onKeydown(e) { switch (e.key) { case "ArrowRight": e.preventDefault(); moveRight(); break; case "ArrowLeft": e.preventDefault(); moveLeft(); break; case "ArrowDown": e.preventDefault(); next(); break; case "ArrowUp": e.preventDefault(); prev(); break; } } return { rootElement, assignTemplateRef, onFocus, onBlur, onKeydown }; } const _sfc_main$A = defineComponent({ name: "CdxButtonGroup", components: { CdxButton, CdxIcon }, props: { /** * Objects describing the buttons in the group. See the ButtonGroupItem type. */ buttons: { type: Array, required: true, validator: (value) => Array.isArray(value) && value.length >= 1 }, /** * Whether the entire group is disabled. * * If this is set to true, all buttons in the group are disabled. Buttons can also be * disabled individually by setting their `disabled` property to true. */ disabled: { type: Boolean, default: false } }, emits: [ /** * Emitted when a button is clicked * * @property {string | number} value The `value` property of the button that was clicked */ "click" ], setup(props) { const { rootElement, assignTemplateRef, onFocus, onBlur, onKeydown } = useButtonGroupKeyboardNav(toRef(props, "buttons")); return { rootElement, assignTemplateRef, onFocus, onBlur, onKeydown, getButtonLabel }; } }); const _hoisted_1$x = { ref: "rootElement", class: "cdx-button-group" }; function _sfc_render$B(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_icon = resolveComponent("cdx-icon"); const _component_cdx_button = resolveComponent("cdx-button"); return openBlock(), createElementBlock( "div", _hoisted_1$x, [ (openBlock(true), createElementBlock( Fragment, null, renderList(_ctx.buttons, (button, index) => { return openBlock(), createBlock(_component_cdx_button, { key: button.value, ref_for: true, ref: (ref2) => _ctx.assignTemplateRef(ref2, index), disabled: button.disabled || _ctx.disabled, "aria-label": button.ariaLabel, onClick: ($event) => _ctx.$emit("click", button.value), onFocus: ($event) => _ctx.onFocus(index), onBlur: _ctx.onBlur, onKeydown: _ctx.onKeydown }, { default: withCtx(() => [ renderSlot(_ctx.$slots, "default", { button }, () => [ button.icon ? (openBlock(), createBlock(_component_cdx_icon, { key: 0, icon: button.icon }, null, 8, ["icon"])) : createCommentVNode("v-if", true), createTextVNode( " " + toDisplayString(_ctx.getButtonLabel(button)), 1 /* TEXT */ ) ]) ]), _: 2 /* DYNAMIC */ }, 1032, ["disabled", "aria-label", "onClick", "onFocus", "onBlur", "onKeydown"]); }), 128 /* KEYED_FRAGMENT */ )) ], 512 /* NEED_PATCH */ ); } const ButtonGroup = /* @__PURE__ */ _export_sfc(_sfc_main$A, [["render", _sfc_render$B]]); const _sfc_main$z = defineComponent({ name: "CdxThumbnail", components: { CdxIcon }, props: { /** * Thumbnail data. */ thumbnail: { type: [Object, null], default: null }, /** * Thumbnail placeholder icon. */ placeholderIcon: { type: [String, Object], default: Y7 } }, setup: (props) => { const thumbnailLoaded = ref(false); const thumbnailStyle = ref({}); const preloadThumbnail = (url) => { const escapedUrl = url.replace(/([\\"\n])/g, "\\$1"); const image = new Image(); image.onload = () => { thumbnailStyle.value = { backgroundImage: 'url("'.concat(escapedUrl, '")') }; thumbnailLoaded.value = true; }; image.onerror = () => { thumbnailLoaded.value = false; }; image.src = escapedUrl; }; onMounted(() => { var _a; if ((_a = props.thumbnail) == null ? void 0 : _a.url) { preloadThumbnail(props.thumbnail.url); } }); watch(toRef(props, "thumbnail"), (newThumbnail, oldThumbnail) => { if (!(newThumbnail == null ? void 0 : newThumbnail.url)) { thumbnailLoaded.value = false; thumbnailStyle.value = {}; return; } if ((oldThumbnail == null ? void 0 : oldThumbnail.url) !== newThumbnail.url) { thumbnailLoaded.value = false; preloadThumbnail(newThumbnail.url); } }, { deep: true }); return { thumbnailStyle, thumbnailLoaded, NoInvertClass }; } }); const _hoisted_1$w = { class: "cdx-thumbnail" }; const _hoisted_2$l = { key: 0, class: "cdx-thumbnail__placeholder" }; function _sfc_render$A(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_icon = resolveComponent("cdx-icon"); return openBlock(), createElementBlock("span", _hoisted_1$w, [ !_ctx.thumbnailLoaded ? (openBlock(), createElementBlock("span", _hoisted_2$l, [ createVNode(_component_cdx_icon, { icon: _ctx.placeholderIcon, class: "cdx-thumbnail__placeholder__icon--vue" }, null, 8, ["icon"]) ])) : createCommentVNode("v-if", true), createVNode(Transition, { name: "cdx-thumbnail__image" }, { default: withCtx(() => [ _ctx.thumbnailLoaded ? (openBlock(), createElementBlock( "span", { key: 0, style: normalizeStyle(_ctx.thumbnailStyle), class: normalizeClass([_ctx.NoInvertClass, "cdx-thumbnail__image"]) }, null, 6 /* CLASS, STYLE */ )) : createCommentVNode("v-if", true) ]), _: 1 /* STABLE */ }) ]); } const CdxThumbnail = /* @__PURE__ */ _export_sfc(_sfc_main$z, [["render", _sfc_render$A]]); const _sfc_main$y = defineComponent({ name: "CdxCard", components: { CdxIcon, CdxThumbnail }, props: { /** * If provided, the Card will be a link to this URL. */ url: { type: String, default: "" }, /** * Icon displayed at the start of the Card. */ icon: { type: [String, Object], default: "" }, /** * Thumbnail image data for the Card. */ thumbnail: { type: [Object, null], default: null }, /** * Option to force a thumbnail layout. * * When set to `true`, the Card will display a Thumbnail. If a `thumbnail` prop was also * provided, the thumbnail image will display. Otherwise, a placeholder icon will display. * * This is useful when displaying groups of Cards when some of the cards have thumbnail * images but some do not. `forceThumbnail` will provide a consistent layout for that group. * * Note that this prop is not needed to display a thumbnail image: if the `thumbnail` prop * is provided, it will display. This prop is only needed to enable the display of the * thumbnail placeholder icon when the `thumbnail` prop is not provided. */ forceThumbnail: { type: Boolean, default: false }, /** * Optional custom icon for the placeholder shown when `forceThumbnail` is true but no * thumbnail is provided. * * Defaults to the default placeholder icon set in the Thumbnail component. */ customPlaceholderIcon: { type: [String, Object], default: void 0 } }, setup(props) { const isLink = computed(() => !!props.url); const contentTag = computed(() => isLink.value ? "a" : "span"); const cardLink = computed(() => isLink.value ? props.url : void 0); return { isLink, contentTag, cardLink }; } }); const _hoisted_1$v = { class: "cdx-card__text" }; const _hoisted_2$k = { class: "cdx-card__text__title" }; const _hoisted_3$d = { key: 0, class: "cdx-card__text__description" }; const _hoisted_4$b = { key: 1, class: "cdx-card__text__supporting-text" }; function _sfc_render$z(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_thumbnail = resolveComponent("cdx-thumbnail"); const _component_cdx_icon = resolveComponent("cdx-icon"); return openBlock(), createBlock(resolveDynamicComponent(_ctx.contentTag), { href: _ctx.cardLink, class: normalizeClass(["cdx-card", { "cdx-card--is-link": _ctx.isLink, // Include dynamic classes in the template so that $slots is reactive. "cdx-card--title-only": !_ctx.$slots.description && !_ctx.$slots["supporting-text"] }]) }, { default: withCtx(() => [ _ctx.thumbnail || _ctx.forceThumbnail ? (openBlock(), createBlock(_component_cdx_thumbnail, { key: 0, thumbnail: _ctx.thumbnail, "placeholder-icon": _ctx.customPlaceholderIcon, class: "cdx-card__thumbnail" }, null, 8, ["thumbnail", "placeholder-icon"])) : _ctx.icon ? (openBlock(), createBlock(_component_cdx_icon, { key: 1, icon: _ctx.icon, class: "cdx-card__icon" }, null, 8, ["icon"])) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_1$v, [ createElementVNode("span", _hoisted_2$k, [ renderSlot(_ctx.$slots, "title") ]), _ctx.$slots.description ? (openBlock(), createElementBlock("span", _hoisted_3$d, [ renderSlot(_ctx.$slots, "description") ])) : createCommentVNode("v-if", true), _ctx.$slots["supporting-text"] ? (openBlock(), createElementBlock("span", _hoisted_4$b, [ renderSlot(_ctx.$slots, "supporting-text") ])) : createCommentVNode("v-if", true) ]) ]), _: 3 /* FORWARDED */ }, 8, ["href", "class"]); } const Card = /* @__PURE__ */ _export_sfc(_sfc_main$y, [["render", _sfc_render$z]]); function useComputedDisabled(disabledProp) { const providedDisabled = inject(DisabledKey, ref(false)); return computed(() => providedDisabled.value || disabledProp.value); } function useFieldData(disabledProp, statusProp, idAttr) { const computedDisabled = useComputedDisabled(disabledProp); const providedStatus = inject(FieldStatusKey, ref("default")); const computedStatus = computed(() => { if ((statusProp == null ? void 0 : statusProp.value) && statusProp.value !== "default") { return statusProp.value; } return providedStatus.value; }); const providedId = inject(FieldInputIdKey, void 0); const computedInputId = computed(() => { var _a; return (_a = providedId == null ? void 0 : providedId.value) != null ? _a : idAttr; }); return { computedDisabled, computedStatus, computedInputId }; } function useSplitAttributes(attrs, internalClasses = computed(() => ({}))) { const rootClasses = computed(() => { const classRecord = __objRest(internalClasses.value, []); if (attrs.class) { const providedClasses = attrs.class.split(" "); providedClasses.forEach((className) => { classRecord[className] = true; }); } return classRecord; }); const rootStyle = computed(() => { if ("style" in attrs) { return attrs.style; } return void 0; }); const otherAttrs = computed(() => { const _a = attrs, { class: _ignoredClass, style: _ignoredStyle } = _a, attrsCopy = __objRest(_a, ["class", "style"]); return attrsCopy; }); return { rootClasses, rootStyle, otherAttrs }; } function useI18n(messageKey, defaultValue, params = []) { const providedI18nFunc = inject("CdxI18nFunction", void 0); return computed(() => { const unwrappedParams = params.map((p) => typeof p === "function" ? p() : p.value); const fromProvidedFunc = providedI18nFunc == null ? void 0 : providedI18nFunc(messageKey, ...unwrappedParams); if (fromProvidedFunc !== void 0 && fromProvidedFunc !== null) { return fromProvidedFunc; } return typeof defaultValue === "function" ? defaultValue(...unwrappedParams) : defaultValue; }); } function useI18nWithOverride(override, messageKey, defaultValue, params = []) { const translatedMessage = useI18n(messageKey, defaultValue, params); return computed(() => override.value || translatedMessage.value); } const _sfc_main$x = defineComponent({ name: "CdxLabel", components: { CdxIcon }, /** * We want the label or legend to inherit attributes, not the root element. */ inheritAttrs: false, props: { /** * Icon before the label text. * * Do not use this if including a start icon within the input component. */ icon: { type: [String, Object], default: null }, /** * Whether the field is optional. * * This will add a flag next to the label indicating that the field is optional. */ optional: { type: Boolean, default: false }, // DEPRECATED: set default to '(optional)' and remove validator (T368444). /** * Text to indicate that the field is optional. * * Omit this prop to use the default value, "(optional)". */ optionalFlag: { type: String, default: "", validator: (value, props) => { if (value.length > 0 && !props.optional) { console.warn( "[CdxLabel]: The boolean `optional` prop is required to show the optional flag.\n\nRefer to https://doc.wikimedia.org/codex/latest/components/demos/label.html#props." ); return false; } return true; } }, /** * Whether the label should be visually hidden. */ visuallyHidden: { type: Boolean, default: false }, /** * Whether this component should output a `<legend>` element. * * Always set this to true when this component is used inside a `<fieldset>` element. Do not * set it to true otherwise. */ isLegend: { type: Boolean, default: false }, /** * The ID of the input/control this label is for. * * Will be added as the `for` attribute of the `<label>`. Not needed for `<legend>`. */ inputId: { type: String, default: "" }, /** * The ID of the description element. * * This ID can be used for the `aria-describedby` attribute of the input. */ descriptionId: { type: String, default: "" }, /** * Whether this label is for a disabled field or input. */ disabled: { type: Boolean, default: false } }, setup(props, { attrs }) { const { computedDisabled } = useFieldData(toRef(props, "disabled")); const internalClasses = computed(() => ({ "cdx-label--visually-hidden": props.visuallyHidden, "cdx-label--disabled": computedDisabled.value })); const { rootClasses, rootStyle, otherAttrs } = useSplitAttributes(attrs, internalClasses); const translatedOptionalFlag = useI18nWithOverride( toRef(props, "optionalFlag"), "cdx-label-optional-flag", "(optional)" ); return { rootClasses, rootStyle, otherAttrs, translatedOptionalFlag }; } }); const _hoisted_1$u = ["for"]; const _hoisted_2$j = { class: "cdx-label__label__text" }; const _hoisted_3$c = { key: 1, class: "cdx-label__label__optional-flag" }; const _hoisted_4$a = ["id"]; const _hoisted_5$9 = { class: "cdx-label__label" }; const _hoisted_6$8 = { class: "cdx-label__label__text" }; const _hoisted_7$3 = { key: 1, class: "cdx-label__label__optional-flag" }; const _hoisted_8$3 = { key: 0, class: "cdx-label__description" }; function _sfc_render$y(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_icon = resolveComponent("cdx-icon"); return !_ctx.isLegend ? (openBlock(), createElementBlock( "div", { key: 0, class: normalizeClass(["cdx-label", _ctx.rootClasses]), style: normalizeStyle(_ctx.rootStyle) }, [ createElementVNode("label", mergeProps({ class: "cdx-label__label", for: _ctx.inputId ? _ctx.inputId : void 0 }, _ctx.otherAttrs), [ _ctx.icon ? (openBlock(), createBlock(_component_cdx_icon, { key: 0, icon: _ctx.icon, class: "cdx-label__label__icon" }, null, 8, ["icon"])) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_2$j, [ renderSlot(_ctx.$slots, "default") ]), _ctx.optionalFlag || _ctx.optional ? (openBlock(), createElementBlock( "span", _hoisted_3$c, toDisplayString(" ") + " " + toDisplayString(_ctx.translatedOptionalFlag), 1 /* TEXT */ )) : createCommentVNode("v-if", true) ], 16, _hoisted_1$u), _ctx.$slots.description && _ctx.$slots.description().length > 0 ? (openBlock(), createElementBlock("span", { key: 0, id: _ctx.descriptionId || void 0, class: "cdx-label__description" }, [ renderSlot(_ctx.$slots, "description") ], 8, _hoisted_4$a)) : createCommentVNode("v-if", true) ], 6 /* CLASS, STYLE */ )) : (openBlock(), createElementBlock( "legend", mergeProps({ key: 1, class: ["cdx-label", _ctx.rootClasses], style: _ctx.rootStyle }, _ctx.otherAttrs), [ createElementVNode("span", _hoisted_5$9, [ _ctx.icon ? (openBlock(), createBlock(_component_cdx_icon, { key: 0, icon: _ctx.icon, class: "cdx-label__label__icon" }, null, 8, ["icon"])) : createCommentVNode("v-if", true), createElementVNode("span", _hoisted_6$8, [ renderSlot(_ctx.$slots, "default") ]), _ctx.optionalFlag || _ctx.optional ? (openBlock(), createElementBlock( "span", _hoisted_7$3, toDisplayString(" ") + " " + toDisplayString(_ctx.translatedOptionalFlag), 1 /* TEXT */ )) : createCommentVNode("v-if", true) ]), _ctx.$slots.description && _ctx.$slots.description().length > 0 ? (openBlock(), createElementBlock("span", _hoisted_8$3, [ renderSlot(_ctx.$slots, "description") ])) : createCommentVNode("v-if", true) ], 16 /* FULL_PROPS */ )); } const CdxLabel = /* @__PURE__ */ _export_sfc(_sfc_main$x, [["render", _sfc_render$y]]); function useLabelChecker(slot, attrs, componentName) { useWarnOnce( () => useSlotContents(slot).length === 0 && !(attrs == null ? void 0 : attrs["aria-label"]) && !(attrs == null ? void 0 : attrs["aria-labelledby"]), "".concat(componentName, ": Inputs must have an associated label. Provide one of the following:\n - A label via the appropriate slot\n - An `aria-label` attribute set to the label text\n - An `aria-labelledby` attribute set to the ID of the label element") ); } function useModelWrapper(modelValueRef, emit, eventName) { return computed({ get: () => modelValueRef.value, // If eventName is undefined, then 'update:modelValue' must be a valid EventName, // but TypeScript's type analysis isn't clever enough to realize that set: (value) => emit(eventName || "update:modelValue", value) }); } const statusValidator$a = makeStringTypeValidator(ValidationStatusTypes); const _sfc_main$w = defineComponent({ name: "CdxCheckbox", components: { CdxLabel }, props: { /** * Value of the checkbox or checkbox group. * * Provided by `v-model` binding in the parent component. */ modelValue: { type: [Boolean, Array], default: false }, /** * HTML "value" attribute to assign to the input. * * Required for input groups. */ inputValue: { type: [String, Number, Boolean], default: false }, /** * HTML "name" attribute to assign to the input. */ name: { type: String, default: null }, /** * Whether the disabled attribute should be added to the input. */ disabled: { type: Boolean, default: false }, /** * Whether the indeterminate visual state should be displayed. * * This is unrelated to the value provided by `v-model`, and the indeterminate visual state * will override the checked or unchecked visual state. */ indeterminate: { type: Boolean, default: false }, /** * Whether the component should display inline. * * By default, `display: block` is set and a margin exists between * sibling components, for a stacked layout. */ inline: { type: Boolean, default: false }, /** * Whether the label should be visually hidden. * * When true, the label will remain accessible to assistive technology. */ hideLabel: { type: Boolean, default: false }, /** * Validation status of the Checkbox. */ status: { type: String, default: "default", validator: statusValidator$a } }, emits: [ /** * Emitted when modelValue changes. * * @property {boolean | string[] | number[]} modelValue The new model value */ "update:modelValue" ], setup(props, { emit, slots, attrs }) { var _a; useLabelChecker((_a = slots.default) == null ? void 0 : _a.call(slots), attrs, "CdxCheckbox"); const { computedDisabled, computedStatus } = useFieldData( toRef(props, "disabled"), toRef(props, "status") ); const rootClasses = computed(() => ({ "cdx-checkbox--inline": props.inline, ["cdx-checkbox--status-".concat(computedStatus.value)]: true })); const customInputClasses = computed(() => ({ "cdx-checkbox__custom-input--inline": props.inline })); const input = ref(); const checkboxId = useId(); const descriptionId = useId(); const wrappedModel = useModelWrapper(toRef(props, "modelValue"), emit); return { rootClasses, computedDisabled, input, checkboxId, descriptionId, wrappedModel, customInputClasses }; } }); const _hoisted_1$t = { class: "cdx-checkbox__wrapper" }; const _hoisted_2$i = ["id", "aria-describedby", "value", "name", "disabled", ".indeterminate"]; function _sfc_render$x(_ctx, _cache, $props, $setup, $data, $options) { const _component_cdx_label = resolveComponent("cdx-label"); return openBlock(), createElementBlock( "div", { class: normalizeClass(["cdx-checkbox", _ctx.rootClasses]) }, [ createElementVNode("div", _hoisted_1$t, [ withDirectives(createElementVNode("input", { id: _ctx.checkboxId, ref: "input", "onUpdate:modelVal