@plexui/vue 0.3.0 → 0.5.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.
@@ -116,6 +116,8 @@ const FieldComponent = defineComponent({
116
116
  orientation: String,
117
117
  /** One line of a FieldGroup: label at the start, control at the end. @default false */
118
118
  row: { type: Boolean, default: false },
119
+ /** On a `row`, the control takes the rest of the line after the label. @default false */
120
+ fill: { type: Boolean, default: false },
119
121
  /** Overrides the generated id set on the control and the label's `for`. A child's own `id` wins over both. */
120
122
  id: String,
121
123
  /** Optically aligns the control's text with surrounding content; passed to the control. */
@@ -172,6 +174,7 @@ const FieldComponent = defineComponent({
172
174
  "data-orientation": orientation,
173
175
  "data-optically-align": opticallyAlign,
174
176
  "data-row": row ? "" : undefined,
177
+ "data-fill": props.fill ? "" : undefined,
175
178
  }, [
176
179
  h("div", { class: s.LabelGroup }, [
177
180
  hasLabelAction
@@ -1 +1 @@
1
- {"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../../src/components/Field/Field.ts"],"names":[],"mappings":"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","sourcesContent":["import clsx, { type ClassValue } from \"clsx\"\nimport {\n Comment,\n Fragment,\n Static,\n Text,\n camelize,\n cloneVNode,\n defineComponent,\n h,\n isVNode,\n useId,\n type PropType,\n type SlotsType,\n type VNode,\n type VNodeArrayChildren,\n type VNodeChild,\n} from \"vue\"\nimport type { ControlSize } from \"@plexui/styles/types\"\nimport { FieldError } from \"../FieldError/index.js\"\nimport { hasContent } from \"../../lib/slotContent.js\"\nimport s from \"@plexui/styles/components/Field/Field.module.css\"\n\n// Vue port of packages/ui/src/components/Field/Field.tsx.\n//\n// - `label`, `description` and `errorMessage` take a string prop or a slot of\n// the same name (the slot wins), like React's ReactNode props.\n// - Children: React accepts an element, which Field clones with the field\n// props, or a render prop `(fieldProps) => ReactNode`, which it leaves alone.\n// Both are the default slot here, which receives the field props:\n// - a slot that reads them (`v-slot=\"fieldProps\"` + `v-bind=\"fieldProps\"`,\n// `v-slot=\"{ id }\"`, `(fieldProps) => h(...)`) is the render prop: its\n// content renders as it is.\n// - a slot that does not read them and holds exactly one element or\n// component gets it cloned like React's `cloneElement`: `opticallyAlign`\n// replaces the child's own, the child's own `id` stays and the label's\n// `for` follows it, `aria-describedby` is joined after the child's own\n// ids, and an explicit `aria-invalid` on the child wins. Template\n// comments do not count as children (JSX comments); the\n// placeholder of a `v-if` that renders nothing does, like `{false}` in a\n// React children array, so `<A v-if=\"x\" /><Input />` is not cloned.\n// - anything else (text, several roots, a `v-for` list) renders as it is,\n// like a React child that is not a single element.\n// - content a wrapper forwards with `<slot />` counts as its own roots, as\n// React's `children` passed on to Field are the elements themselves.\n// - As in React only `class` reaches the root element; other attributes are\n// dropped. On a `row` they all reach it, as React's rest props do.\n\nexport type FieldChildProps = {\n id: string\n /** The label's id. Bind it to a control that the label's `for` cannot name, such as a Select trigger. */\n \"aria-labelledby\"?: string\n \"aria-describedby\"?: string\n \"aria-invalid\"?: boolean\n opticallyAlign?: \"start\" | \"end\"\n}\n\ntype Props = Record<string, unknown>\n\nconst CONTROL_SIZES: ReadonlySet<unknown> = new Set([\"3xs\", \"2xs\", \"xs\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\", \"3xl\"])\n\n/** The slot props, recording whether the slot read them (the render-prop form). */\nconst trackUse = (target: FieldChildProps) => {\n const state = { used: false }\n const proxy = new Proxy(target, {\n get(object, key, receiver) {\n state.used = true\n return Reflect.get(object, key, receiver)\n },\n has(object, key) {\n state.used = true\n return Reflect.has(object, key)\n },\n ownKeys(object) {\n state.used = true\n return Reflect.ownKeys(object)\n },\n getOwnPropertyDescriptor(object, key) {\n state.used = true\n return Reflect.getOwnPropertyDescriptor(object, key)\n },\n })\n return { proxy, state }\n}\n\n/** Like React's `isValidElement` for a slot root: an element or a component. */\nconst isElementVNode = (node: VNode) => {\n const { type } = node\n if (type === Fragment || type === Text || type === Comment || type === Static) return false\n if (typeof type === \"object\" && type !== null && (\"__isTeleport\" in type || \"__isSuspense\" in type)) return false\n return true\n}\n\n/**\n * Template comments (`<!-- note -->`) are no children, like JSX comments.\n * The empty placeholder of a `v-if` that renders nothing (or of a `false`\n * child) still counts, like `{false}` in a React children array.\n */\nconst isTemplateComment = (node: VNodeArrayChildren[number]) =>\n isVNode(node) && node.type === Comment && !!node.children && node.children !== \"v-if\"\n\n/**\n * Unwraps content forwarded through a wrapper's `<slot />`: the fragment\n * `renderSlot` creates, keyed `_<slot name>`.\n */\nconst unwrapForwardedSlots = (nodes: VNodeArrayChildren): VNodeArrayChildren =>\n nodes.flatMap((node) =>\n isVNode(node) &&\n node.type === Fragment &&\n typeof node.key === \"string\" &&\n node.key.startsWith(\"_\") &&\n Array.isArray(node.children)\n ? unwrapForwardedSlots(node.children)\n : [node],\n )\n\n/** The one element a non-render-prop slot holds, if it holds exactly one. */\nconst singleElement = (nodes: VNodeArrayChildren): VNode | undefined => {\n const roots = unwrapForwardedSlots(nodes).filter((node) => !isTemplateComment(node))\n if (roots.length !== 1) return undefined\n const [root] = roots\n return isVNode(root) && isElementVNode(root) ? root : undefined\n}\n\n/** A child prop under its attribute name or its camelCase prop name. */\nconst childProp = (props: Props, name: string) => props[name] ?? props[camelize(name)]\n\n/**\n * `cloneElement(child, fieldProps)` with React Field's merging rules. A child\n * without its own name (`aria-label`, `aria-labelledby`, `label`, a `#label`\n * slot) is also labelled by the field's label, which names triggers `for`\n * cannot reach.\n */\nconst cloneWithFieldProps = (child: VNode, fieldChildProps: FieldChildProps, labelId: string): VNode => {\n const own: Props = { ...(child.props ?? {}) }\n const childDescribedBy = childProp(own, \"aria-describedby\") as string | undefined\n const childInvalid = childProp(own, \"aria-invalid\")\n const childSlots = child.children\n const childNamed =\n childProp(own, \"aria-label\") != null ||\n childProp(own, \"aria-labelledby\") != null ||\n own.label != null ||\n (childSlots != null && typeof childSlots === \"object\" && !Array.isArray(childSlots) && \"label\" in childSlots)\n\n const overrides: Props = {\n ...fieldChildProps,\n // Merge with the child's own associations instead of overwriting them\n \"aria-describedby\": [childDescribedBy, fieldChildProps[\"aria-describedby\"]].filter(Boolean).join(\" \") || undefined,\n \"aria-invalid\": childInvalid ?? fieldChildProps[\"aria-invalid\"],\n ...(!childNamed && { \"aria-labelledby\": labelId }),\n }\n\n // One spelling per prop, so the field's value is the one that applies\n for (const key of Object.keys(overrides)) {\n for (const spelling of [key, camelize(key), key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)]) {\n delete own[spelling]\n }\n }\n\n return cloneVNode({ ...child, props: own } as VNode, overrides)\n}\n\nconst FieldComponent = defineComponent({\n name: \"Field\",\n inheritAttrs: false,\n props: {\n /** Label text for the field (or the `label` slot) */\n label: String,\n /** Helper text below the label, linked via `aria-describedby` (or the `description` slot) */\n description: String,\n /**\n * Error message below the control (or the `errorMessage` slot). When set,\n * the control gets `aria-invalid=\"true\"`. Rendered with FieldError.\n */\n errorMessage: String,\n /** Content at the end of the label row, such as a link that acts on the field (or the `labelAction` slot) */\n labelAction: String,\n /** Font size of the label, to match the control's size. @default the child control's `size`, else \"md\" */\n size: String as PropType<ControlSize>,\n /** Shows a required asterisk after the label. Visual only: no `required` attribute. @default false */\n required: { type: Boolean, default: false },\n /** Layout direction of label and control. @default \"horizontal\" on a `row`, else \"vertical\" */\n orientation: String as PropType<\"vertical\" | \"horizontal\">,\n /** One line of a FieldGroup: label at the start, control at the end. @default false */\n row: { type: Boolean, default: false },\n /** Overrides the generated id set on the control and the label's `for`. A child's own `id` wins over both. */\n id: String,\n /** Optically aligns the control's text with surrounding content; passed to the control. */\n opticallyAlign: String as PropType<\"start\" | \"end\">,\n },\n slots: Object as SlotsType<{\n /** The control. Read the props to render them yourself (React's render prop). */\n default?: (fieldProps: FieldChildProps) => VNodeChild\n label?: () => VNodeChild\n labelAction?: () => VNodeChild\n description?: () => VNodeChild\n errorMessage?: () => VNodeChild\n }>,\n setup(props, { attrs, slots }) {\n const generatedId = useId()\n\n return () => {\n const { required, row, opticallyAlign } = props\n const orientation = props.orientation ?? (row ? \"horizontal\" : \"vertical\")\n const fieldId = props.id || `field-${generatedId}`\n const labelId = `${fieldId}-label`\n\n const description = slots.description ? slots.description() : props.description\n const hasDescription = slots.description ? hasContent(description as VNodeArrayChildren) : !!description\n const errorMessage = slots.errorMessage ? slots.errorMessage() : props.errorMessage\n const hasError = slots.errorMessage ? hasContent(errorMessage as VNodeArrayChildren) : !!errorMessage\n\n const descriptionId = hasDescription ? `${fieldId}-description` : undefined\n const errorId = hasError ? `${fieldId}-error` : undefined\n\n // Build aria-describedby from description + error IDs\n const ariaDescribedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined\n const invalid = hasError\n\n // Props to inject into the child control\n const fieldChildProps: FieldChildProps = {\n \"id\": fieldId,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": invalid || undefined,\n ...(opticallyAlign && { opticallyAlign }),\n }\n\n // Resolve the children\n let resolvedChildren: VNodeArrayChildren | undefined\n let childSize: unknown\n // The control's id, which the label's `for` has to match\n let controlId = fieldId\n if (slots.default) {\n const { proxy, state } = trackUse({ ...fieldChildProps, \"aria-labelledby\": labelId })\n const nodes = slots.default(proxy) as VNodeArrayChildren\n const child = state.used ? undefined : singleElement(nodes)\n childSize = child?.props?.size\n controlId = (child?.props?.id as string | undefined) || fieldId\n resolvedChildren = child ? [cloneWithFieldProps(child, { ...fieldChildProps, id: controlId }, labelId)] : nodes\n }\n const size = props.size ?? (CONTROL_SIZES.has(childSize) ? (childSize as ControlSize) : \"md\")\n\n const labelAction = slots.labelAction ? slots.labelAction() : props.labelAction\n const hasLabelAction = slots.labelAction ? hasContent(labelAction as VNodeArrayChildren) : !!labelAction\n const labelElement = h(\"label\", { class: s.Label, id: labelId, for: controlId }, [\n slots.label ? slots.label() : props.label,\n required ? h(\"span\", { \"class\": s.RequiredIndicator, \"aria-hidden\": \"true\" }, \"*\") : null,\n ])\n\n return h(\n \"div\",\n {\n ...(row && attrs),\n \"class\": clsx(s.Field, attrs.class as ClassValue),\n \"data-size\": size,\n \"data-orientation\": orientation,\n \"data-optically-align\": opticallyAlign,\n \"data-row\": row ? \"\" : undefined,\n },\n [\n h(\"div\", { class: s.LabelGroup }, [\n hasLabelAction\n ? h(\"div\", { class: s.LabelRow }, [labelElement, h(\"div\", { class: s.LabelAction }, [labelAction as VNodeChild])])\n : labelElement,\n hasDescription ? h(\"div\", { class: s.Description, id: descriptionId }, [description as VNodeChild]) : null,\n ]),\n h(\"div\", { class: s.Content }, [\n h(\"div\", { class: s.Control }, resolvedChildren),\n hasError ? h(FieldError, { id: errorId }, () => [errorMessage as VNodeChild]) : null,\n ]),\n ],\n )\n }\n },\n})\n\ntype FieldOwnProps = InstanceType<typeof FieldComponent>[\"$props\"]\n\n/** Field props; `class` reaches the root element. */\nexport type FieldProps = FieldOwnProps & { class?: ClassValue }\n\n/** Form field wrapper with label, description, error and accessibility linking. */\nexport const Field = FieldComponent as typeof FieldComponent & { new (): { $props: FieldProps } }\n"]}
1
+ {"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../../src/components/Field/Field.ts"],"names":[],"mappings":"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","sourcesContent":["import clsx, { type ClassValue } from \"clsx\"\nimport {\n Comment,\n Fragment,\n Static,\n Text,\n camelize,\n cloneVNode,\n defineComponent,\n h,\n isVNode,\n useId,\n type PropType,\n type SlotsType,\n type VNode,\n type VNodeArrayChildren,\n type VNodeChild,\n} from \"vue\"\nimport type { ControlSize } from \"@plexui/styles/types\"\nimport { FieldError } from \"../FieldError/index.js\"\nimport { hasContent } from \"../../lib/slotContent.js\"\nimport s from \"@plexui/styles/components/Field/Field.module.css\"\n\n// Vue port of packages/ui/src/components/Field/Field.tsx.\n//\n// - `label`, `description` and `errorMessage` take a string prop or a slot of\n// the same name (the slot wins), like React's ReactNode props.\n// - Children: React accepts an element, which Field clones with the field\n// props, or a render prop `(fieldProps) => ReactNode`, which it leaves alone.\n// Both are the default slot here, which receives the field props:\n// - a slot that reads them (`v-slot=\"fieldProps\"` + `v-bind=\"fieldProps\"`,\n// `v-slot=\"{ id }\"`, `(fieldProps) => h(...)`) is the render prop: its\n// content renders as it is.\n// - a slot that does not read them and holds exactly one element or\n// component gets it cloned like React's `cloneElement`: `opticallyAlign`\n// replaces the child's own, the child's own `id` stays and the label's\n// `for` follows it, `aria-describedby` is joined after the child's own\n// ids, and an explicit `aria-invalid` on the child wins. Template\n// comments do not count as children (JSX comments); the\n// placeholder of a `v-if` that renders nothing does, like `{false}` in a\n// React children array, so `<A v-if=\"x\" /><Input />` is not cloned.\n// - anything else (text, several roots, a `v-for` list) renders as it is,\n// like a React child that is not a single element.\n// - content a wrapper forwards with `<slot />` counts as its own roots, as\n// React's `children` passed on to Field are the elements themselves.\n// - As in React only `class` reaches the root element; other attributes are\n// dropped. On a `row` they all reach it, as React's rest props do.\n\nexport type FieldChildProps = {\n id: string\n /** The label's id. Bind it to a control that the label's `for` cannot name, such as a Select trigger. */\n \"aria-labelledby\"?: string\n \"aria-describedby\"?: string\n \"aria-invalid\"?: boolean\n opticallyAlign?: \"start\" | \"end\"\n}\n\ntype Props = Record<string, unknown>\n\nconst CONTROL_SIZES: ReadonlySet<unknown> = new Set([\"3xs\", \"2xs\", \"xs\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\", \"3xl\"])\n\n/** The slot props, recording whether the slot read them (the render-prop form). */\nconst trackUse = (target: FieldChildProps) => {\n const state = { used: false }\n const proxy = new Proxy(target, {\n get(object, key, receiver) {\n state.used = true\n return Reflect.get(object, key, receiver)\n },\n has(object, key) {\n state.used = true\n return Reflect.has(object, key)\n },\n ownKeys(object) {\n state.used = true\n return Reflect.ownKeys(object)\n },\n getOwnPropertyDescriptor(object, key) {\n state.used = true\n return Reflect.getOwnPropertyDescriptor(object, key)\n },\n })\n return { proxy, state }\n}\n\n/** Like React's `isValidElement` for a slot root: an element or a component. */\nconst isElementVNode = (node: VNode) => {\n const { type } = node\n if (type === Fragment || type === Text || type === Comment || type === Static) return false\n if (typeof type === \"object\" && type !== null && (\"__isTeleport\" in type || \"__isSuspense\" in type)) return false\n return true\n}\n\n/**\n * Template comments (`<!-- note -->`) are no children, like JSX comments.\n * The empty placeholder of a `v-if` that renders nothing (or of a `false`\n * child) still counts, like `{false}` in a React children array.\n */\nconst isTemplateComment = (node: VNodeArrayChildren[number]) =>\n isVNode(node) && node.type === Comment && !!node.children && node.children !== \"v-if\"\n\n/**\n * Unwraps content forwarded through a wrapper's `<slot />`: the fragment\n * `renderSlot` creates, keyed `_<slot name>`.\n */\nconst unwrapForwardedSlots = (nodes: VNodeArrayChildren): VNodeArrayChildren =>\n nodes.flatMap((node) =>\n isVNode(node) &&\n node.type === Fragment &&\n typeof node.key === \"string\" &&\n node.key.startsWith(\"_\") &&\n Array.isArray(node.children)\n ? unwrapForwardedSlots(node.children)\n : [node],\n )\n\n/** The one element a non-render-prop slot holds, if it holds exactly one. */\nconst singleElement = (nodes: VNodeArrayChildren): VNode | undefined => {\n const roots = unwrapForwardedSlots(nodes).filter((node) => !isTemplateComment(node))\n if (roots.length !== 1) return undefined\n const [root] = roots\n return isVNode(root) && isElementVNode(root) ? root : undefined\n}\n\n/** A child prop under its attribute name or its camelCase prop name. */\nconst childProp = (props: Props, name: string) => props[name] ?? props[camelize(name)]\n\n/**\n * `cloneElement(child, fieldProps)` with React Field's merging rules. A child\n * without its own name (`aria-label`, `aria-labelledby`, `label`, a `#label`\n * slot) is also labelled by the field's label, which names triggers `for`\n * cannot reach.\n */\nconst cloneWithFieldProps = (child: VNode, fieldChildProps: FieldChildProps, labelId: string): VNode => {\n const own: Props = { ...(child.props ?? {}) }\n const childDescribedBy = childProp(own, \"aria-describedby\") as string | undefined\n const childInvalid = childProp(own, \"aria-invalid\")\n const childSlots = child.children\n const childNamed =\n childProp(own, \"aria-label\") != null ||\n childProp(own, \"aria-labelledby\") != null ||\n own.label != null ||\n (childSlots != null && typeof childSlots === \"object\" && !Array.isArray(childSlots) && \"label\" in childSlots)\n\n const overrides: Props = {\n ...fieldChildProps,\n // Merge with the child's own associations instead of overwriting them\n \"aria-describedby\": [childDescribedBy, fieldChildProps[\"aria-describedby\"]].filter(Boolean).join(\" \") || undefined,\n \"aria-invalid\": childInvalid ?? fieldChildProps[\"aria-invalid\"],\n ...(!childNamed && { \"aria-labelledby\": labelId }),\n }\n\n // One spelling per prop, so the field's value is the one that applies\n for (const key of Object.keys(overrides)) {\n for (const spelling of [key, camelize(key), key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)]) {\n delete own[spelling]\n }\n }\n\n return cloneVNode({ ...child, props: own } as VNode, overrides)\n}\n\nconst FieldComponent = defineComponent({\n name: \"Field\",\n inheritAttrs: false,\n props: {\n /** Label text for the field (or the `label` slot) */\n label: String,\n /** Helper text below the label, linked via `aria-describedby` (or the `description` slot) */\n description: String,\n /**\n * Error message below the control (or the `errorMessage` slot). When set,\n * the control gets `aria-invalid=\"true\"`. Rendered with FieldError.\n */\n errorMessage: String,\n /** Content at the end of the label row, such as a link that acts on the field (or the `labelAction` slot) */\n labelAction: String,\n /** Font size of the label, to match the control's size. @default the child control's `size`, else \"md\" */\n size: String as PropType<ControlSize>,\n /** Shows a required asterisk after the label. Visual only: no `required` attribute. @default false */\n required: { type: Boolean, default: false },\n /** Layout direction of label and control. @default \"horizontal\" on a `row`, else \"vertical\" */\n orientation: String as PropType<\"vertical\" | \"horizontal\">,\n /** One line of a FieldGroup: label at the start, control at the end. @default false */\n row: { type: Boolean, default: false },\n /** On a `row`, the control takes the rest of the line after the label. @default false */\n fill: { type: Boolean, default: false },\n /** Overrides the generated id set on the control and the label's `for`. A child's own `id` wins over both. */\n id: String,\n /** Optically aligns the control's text with surrounding content; passed to the control. */\n opticallyAlign: String as PropType<\"start\" | \"end\">,\n },\n slots: Object as SlotsType<{\n /** The control. Read the props to render them yourself (React's render prop). */\n default?: (fieldProps: FieldChildProps) => VNodeChild\n label?: () => VNodeChild\n labelAction?: () => VNodeChild\n description?: () => VNodeChild\n errorMessage?: () => VNodeChild\n }>,\n setup(props, { attrs, slots }) {\n const generatedId = useId()\n\n return () => {\n const { required, row, opticallyAlign } = props\n const orientation = props.orientation ?? (row ? \"horizontal\" : \"vertical\")\n const fieldId = props.id || `field-${generatedId}`\n const labelId = `${fieldId}-label`\n\n const description = slots.description ? slots.description() : props.description\n const hasDescription = slots.description ? hasContent(description as VNodeArrayChildren) : !!description\n const errorMessage = slots.errorMessage ? slots.errorMessage() : props.errorMessage\n const hasError = slots.errorMessage ? hasContent(errorMessage as VNodeArrayChildren) : !!errorMessage\n\n const descriptionId = hasDescription ? `${fieldId}-description` : undefined\n const errorId = hasError ? `${fieldId}-error` : undefined\n\n // Build aria-describedby from description + error IDs\n const ariaDescribedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined\n const invalid = hasError\n\n // Props to inject into the child control\n const fieldChildProps: FieldChildProps = {\n \"id\": fieldId,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": invalid || undefined,\n ...(opticallyAlign && { opticallyAlign }),\n }\n\n // Resolve the children\n let resolvedChildren: VNodeArrayChildren | undefined\n let childSize: unknown\n // The control's id, which the label's `for` has to match\n let controlId = fieldId\n if (slots.default) {\n const { proxy, state } = trackUse({ ...fieldChildProps, \"aria-labelledby\": labelId })\n const nodes = slots.default(proxy) as VNodeArrayChildren\n const child = state.used ? undefined : singleElement(nodes)\n childSize = child?.props?.size\n controlId = (child?.props?.id as string | undefined) || fieldId\n resolvedChildren = child ? [cloneWithFieldProps(child, { ...fieldChildProps, id: controlId }, labelId)] : nodes\n }\n const size = props.size ?? (CONTROL_SIZES.has(childSize) ? (childSize as ControlSize) : \"md\")\n\n const labelAction = slots.labelAction ? slots.labelAction() : props.labelAction\n const hasLabelAction = slots.labelAction ? hasContent(labelAction as VNodeArrayChildren) : !!labelAction\n const labelElement = h(\"label\", { class: s.Label, id: labelId, for: controlId }, [\n slots.label ? slots.label() : props.label,\n required ? h(\"span\", { \"class\": s.RequiredIndicator, \"aria-hidden\": \"true\" }, \"*\") : null,\n ])\n\n return h(\n \"div\",\n {\n ...(row && attrs),\n \"class\": clsx(s.Field, attrs.class as ClassValue),\n \"data-size\": size,\n \"data-orientation\": orientation,\n \"data-optically-align\": opticallyAlign,\n \"data-row\": row ? \"\" : undefined,\n \"data-fill\": props.fill ? \"\" : undefined,\n },\n [\n h(\"div\", { class: s.LabelGroup }, [\n hasLabelAction\n ? h(\"div\", { class: s.LabelRow }, [labelElement, h(\"div\", { class: s.LabelAction }, [labelAction as VNodeChild])])\n : labelElement,\n hasDescription ? h(\"div\", { class: s.Description, id: descriptionId }, [description as VNodeChild]) : null,\n ]),\n h(\"div\", { class: s.Content }, [\n h(\"div\", { class: s.Control }, resolvedChildren),\n hasError ? h(FieldError, { id: errorId }, () => [errorMessage as VNodeChild]) : null,\n ]),\n ],\n )\n }\n },\n})\n\ntype FieldOwnProps = InstanceType<typeof FieldComponent>[\"$props\"]\n\n/** Field props; `class` reaches the root element. */\nexport type FieldProps = FieldOwnProps & { class?: ClassValue }\n\n/** Form field wrapper with label, description, error and accessibility linking. */\nexport const Field = FieldComponent as typeof FieldComponent & { new (): { $props: FieldProps } }\n"]}
@@ -0,0 +1,89 @@
1
+ import { computed, defineComponent, h, inject, mergeProps, provide, ref, } from "vue";
2
+ import s from "@plexui/styles/components/Page/Page.module.css";
3
+ // A trackpad's small settle at the top must not flash the line.
4
+ const SCROLLED_AFTER = 4;
5
+ const PAGE_CONTEXT = Symbol("Page");
6
+ function usePageContext(part) {
7
+ const scrolled = inject(PAGE_CONTEXT, null);
8
+ if (!scrolled) {
9
+ throw new Error(`${part} must be used within Page`);
10
+ }
11
+ return scrolled;
12
+ }
13
+ const PageComponent = defineComponent({
14
+ name: "Page",
15
+ props: {
16
+ /**
17
+ * Width of the column that header and content share: `"full"` (edge to
18
+ * edge, for tables), `"wide"` (1280px, centred, for overviews) or `"column"`
19
+ * (768px, centred, for settings and forms). Set `--page-width` on the page
20
+ * for any other width.
21
+ * @default "full"
22
+ */
23
+ width: { type: String, default: "full" },
24
+ },
25
+ setup(props, { slots }) {
26
+ provide(PAGE_CONTEXT, ref(false));
27
+ return () => h("div", { "class": s.Page, "data-width": props.width }, slots.default?.());
28
+ },
29
+ });
30
+ export const Page = PageComponent;
31
+ /** The band above the content, one column with it (React `Page.Header`). */
32
+ export const PageHeader = defineComponent({
33
+ name: "PageHeader",
34
+ props: {
35
+ /**
36
+ * Shows the line, and the glass on a phone, once the content has scrolled
37
+ * under the header. Turn it off when the content already draws a line of
38
+ * its own at that place.
39
+ * @default true
40
+ */
41
+ divider: { type: Boolean, default: true },
42
+ },
43
+ setup(props, { slots }) {
44
+ const scrolled = usePageContext("PageHeader");
45
+ const line = computed(() => props.divider && scrolled.value);
46
+ return () => h("div", { "class": s.Header, "data-scrolled": line.value ? "" : undefined }, [
47
+ h("div", { class: s.Head }, slots.default?.()),
48
+ ]);
49
+ },
50
+ });
51
+ function part(name, tag, className) {
52
+ return defineComponent({
53
+ name,
54
+ setup(_, { slots }) {
55
+ return () => h(tag, { class: className }, slots.default?.());
56
+ },
57
+ });
58
+ }
59
+ /** The row of the title and the actions (React `Page.Bar`). */
60
+ export const PageBar = part("PageBar", "div", s.Bar);
61
+ /** Title with what stands beside it, a subtitle under it on a phone (React `Page.Heading`). */
62
+ export const PageHeading = part("PageHeading", "div", s.Heading);
63
+ /** Page heading, an `<h1>` (React `Page.Title`). */
64
+ export const PageTitle = part("PageTitle", "h1", s.Title);
65
+ /** Status of the page, a `<p>` (React `Page.Subtitle`). */
66
+ export const PageSubtitle = part("PageSubtitle", "p", s.Subtitle);
67
+ /** Buttons on the trailing side of the bar (React `Page.Actions`). */
68
+ export const PageActions = part("PageActions", "div", s.Actions);
69
+ /** The part of the page that scrolls (React `Page.Content`). */
70
+ export const PageContent = defineComponent({
71
+ name: "PageContent",
72
+ inheritAttrs: false,
73
+ props: {
74
+ /**
75
+ * The content fills the page and scrolls inside itself, as a table does:
76
+ * the page stops scrolling from 768px up.
77
+ * @default false
78
+ */
79
+ fill: { type: Boolean, default: false },
80
+ },
81
+ setup(props, { attrs, slots }) {
82
+ const scrolled = usePageContext("PageContent");
83
+ const onScroll = (event) => {
84
+ scrolled.value = event.currentTarget.scrollTop > SCROLLED_AFTER;
85
+ };
86
+ return () => h("div", mergeProps({ "class": s.Content, "data-fill": props.fill ? "" : undefined, onScroll }, attrs), [h("div", { class: s.Column }, slots.default?.())]);
87
+ },
88
+ });
89
+ //# sourceMappingURL=Page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Page.js","sourceRoot":"","sources":["../../../../src/components/Page/Page.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n computed,\n defineComponent,\n h,\n inject,\n mergeProps,\n provide,\n ref,\n type HTMLAttributes,\n type InjectionKey,\n type PropType,\n type Ref,\n} from \"vue\"\nimport s from \"@plexui/styles/components/Page/Page.module.css\"\n\n// Vue port of packages/ui/src/components/Page/Page.tsx. Exports are flat\n// (`PageHeader` for `Page.Header`, ...). As in React, caller attributes are\n// applied after the page's own (`class` is merged), so they win.\n\nexport type PageWidth = \"full\" | \"wide\" | \"column\"\n\n// A trackpad's small settle at the top must not flash the line.\nconst SCROLLED_AFTER = 4\n\nconst PAGE_CONTEXT: InjectionKey<Ref<boolean>> = Symbol(\"Page\")\n\nfunction usePageContext(part: string): Ref<boolean> {\n const scrolled = inject(PAGE_CONTEXT, null)\n if (!scrolled) {\n throw new Error(`${part} must be used within Page`)\n }\n return scrolled\n}\n\nconst PageComponent = defineComponent({\n name: \"Page\",\n props: {\n /**\n * Width of the column that header and content share: `\"full\"` (edge to\n * edge, for tables), `\"wide\"` (1280px, centred, for overviews) or `\"column\"`\n * (768px, centred, for settings and forms). Set `--page-width` on the page\n * for any other width.\n * @default \"full\"\n */\n width: { type: String as PropType<PageWidth>, default: \"full\" },\n },\n setup(props, { slots }) {\n provide(PAGE_CONTEXT, ref(false))\n\n return () => h(\"div\", { \"class\": s.Page, \"data-width\": props.width }, slots.default?.())\n },\n})\n\n/** Props of `Page`. */\nexport type PageProps = { width?: PageWidth } & HTMLAttributes\n\nexport const Page = PageComponent as typeof PageComponent & { new (): { $props: PageProps } }\n\n/** The band above the content, one column with it (React `Page.Header`). */\nexport const PageHeader = defineComponent({\n name: \"PageHeader\",\n props: {\n /**\n * Shows the line, and the glass on a phone, once the content has scrolled\n * under the header. Turn it off when the content already draws a line of\n * its own at that place.\n * @default true\n */\n divider: { type: Boolean, default: true },\n },\n setup(props, { slots }) {\n const scrolled = usePageContext(\"PageHeader\")\n const line = computed(() => props.divider && scrolled.value)\n\n return () =>\n h(\"div\", { \"class\": s.Header, \"data-scrolled\": line.value ? \"\" : undefined }, [\n h(\"div\", { class: s.Head }, slots.default?.()),\n ])\n },\n})\n\nfunction part(name: string, tag: string, className: string) {\n return defineComponent({\n name,\n setup(_, { slots }) {\n return () => h(tag, { class: className }, slots.default?.())\n },\n })\n}\n\n/** The row of the title and the actions (React `Page.Bar`). */\nexport const PageBar = part(\"PageBar\", \"div\", s.Bar)\n/** Title with what stands beside it, a subtitle under it on a phone (React `Page.Heading`). */\nexport const PageHeading = part(\"PageHeading\", \"div\", s.Heading)\n/** Page heading, an `<h1>` (React `Page.Title`). */\nexport const PageTitle = part(\"PageTitle\", \"h1\", s.Title)\n/** Status of the page, a `<p>` (React `Page.Subtitle`). */\nexport const PageSubtitle = part(\"PageSubtitle\", \"p\", s.Subtitle)\n/** Buttons on the trailing side of the bar (React `Page.Actions`). */\nexport const PageActions = part(\"PageActions\", \"div\", s.Actions)\n\n/** The part of the page that scrolls (React `Page.Content`). */\nexport const PageContent = defineComponent({\n name: \"PageContent\",\n inheritAttrs: false,\n props: {\n /**\n * The content fills the page and scrolls inside itself, as a table does:\n * the page stops scrolling from 768px up.\n * @default false\n */\n fill: { type: Boolean, default: false },\n },\n setup(props, { attrs, slots }) {\n const scrolled = usePageContext(\"PageContent\")\n\n const onScroll = (event: Event) => {\n scrolled.value = (event.currentTarget as HTMLElement).scrollTop > SCROLLED_AFTER\n }\n\n return () =>\n h(\n \"div\",\n mergeProps(\n { \"class\": s.Content, \"data-fill\": props.fill ? \"\" : undefined, onScroll },\n attrs,\n ),\n [h(\"div\", { class: s.Column }, slots.default?.())],\n )\n },\n})\n\n/** Props of the Page parts: native attributes of their element. */\nexport type PageSlotProps = HTMLAttributes\n"]}
@@ -0,0 +1,2 @@
1
+ export { Page, PageActions, PageBar, PageContent, PageHeader, PageHeading, PageSubtitle, PageTitle, } from "./Page.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/Page/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,WAAW,EACX,OAAO,EACP,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EACZ,SAAS,GAIV,MAAM,WAAW,CAAA","sourcesContent":["export {\n Page,\n PageActions,\n PageBar,\n PageContent,\n PageHeader,\n PageHeading,\n PageSubtitle,\n PageTitle,\n type PageProps,\n type PageSlotProps,\n type PageWidth,\n} from \"./Page.js\"\n"]}
@@ -71,12 +71,12 @@ const selectProps = {
71
71
  alignOffset: Number,
72
72
  /** Collision detection of the menu. @default true */
73
73
  avoidCollisions: { type: Boolean, default: true },
74
- /** Width of the menu. @default "auto" */
74
+ /** Width of the menu. @default the trigger width (fits the options when not block) */
75
75
  listWidth: [Number, String],
76
- /** `min-width` of the menu, in pixels. @default the trigger width (300 when not block) */
76
+ /** `min-width` of the menu, in pixels. @default the trigger width */
77
77
  listMinWidth: [Number, String],
78
- /** `max-width` of the menu, in pixels. @default "auto" */
79
- listMaxWidth: { type: [Number, String], default: "auto" },
78
+ /** `max-width` of the menu, in pixels. @default "auto" (300 when not block) */
79
+ listMaxWidth: [Number, String],
80
80
  /** Predicate used to filter searches */
81
81
  searchPredicate: Function,
82
82
  /** Placeholder of the search input */
@@ -149,8 +149,6 @@ const SelectComponent = defineComponent({
149
149
  const align = computed(() => props.align ?? (block.value ? "center" : "start"));
150
150
  // Flush with the trigger's edge, as the prop documents
151
151
  const alignOffset = computed(() => props.alignOffset ?? 0);
152
- // A menu is never narrower than the field it belongs to. Inline selects keep their 300px floor.
153
- const listMinWidth = computed(() => props.listMinWidth ?? (block.value ? undefined : 300));
154
152
  const change = (selection) => {
155
153
  emit("update:value", Array.isArray(selection) ? selection.map((option) => option.value) : selection.value);
156
154
  emit("change", selection);
@@ -196,6 +194,11 @@ const SelectComponent = defineComponent({
196
194
  });
197
195
  // Locking down searchable count to a single value
198
196
  const searchable = computed(() => optionsCount.value > 15);
197
+ // A block menu matches its field. An inline one fits its options: no narrower than
198
+ // its trigger (the CSS fallback reads the trigger width), no wider than 300px.
199
+ const fitsOptions = computed(() => !block.value && props.listWidth === undefined);
200
+ const listWidth = computed(() => props.listWidth ?? (fitsOptions.value ? "auto" : undefined));
201
+ const listMaxWidth = computed(() => props.listMaxWidth ?? (fitsOptions.value ? 300 : "auto"));
199
202
  const slotsVersion = ref(0);
200
203
  onBeforeUpdate(() => {
201
204
  slotsVersion.value++;
@@ -209,7 +212,8 @@ const SelectComponent = defineComponent({
209
212
  block,
210
213
  align,
211
214
  alignOffset,
212
- listMinWidth,
215
+ listWidth,
216
+ listMaxWidth,
213
217
  searchable,
214
218
  actions,
215
219
  onSelect,
@@ -518,7 +522,7 @@ const SelectContentElement = markRaw(defineComponent({
518
522
  const SelectPopoverContent = defineComponent({
519
523
  name: "SelectPopoverContent",
520
524
  setup() {
521
- const { props, align, alignOffset, listMinWidth } = useSelectContext();
525
+ const { props, align, alignOffset, listWidth, listMaxWidth } = useSelectContext();
522
526
  const { handleRootOpenChange, popoverTriggerEl } = inject(CustomSelectContextKey);
523
527
  // Radix (1.8.1) dismisses on the click that follows a primary pointer down outside
524
528
  const { onPointerDownOutside, onFocusOutside } = useDeferredPointerDownOutside((originalEvent) => {
@@ -545,9 +549,9 @@ const SelectPopoverContent = defineComponent({
545
549
  onPointerDownOutside,
546
550
  onFocusOutside,
547
551
  style: toCssVariables({
548
- "select-list-width": props.listWidth,
549
- "select-list-min-width": listMinWidth.value,
550
- "select-list-max-width": props.listMaxWidth,
552
+ "select-list-width": listWidth.value,
553
+ "select-list-min-width": props.listMinWidth,
554
+ "select-list-max-width": listMaxWidth.value,
551
555
  }),
552
556
  }, { default: () => h(CustomSelectMenu) });
553
557
  },
@@ -590,7 +594,7 @@ const focusMounted = (element) => {
590
594
  const CustomSelectMenu = defineComponent({
591
595
  name: "CustomSelectMenu",
592
596
  setup() {
593
- const { props, searchable, searchPredicate } = useSelectContext();
597
+ const { props, searchable, searchPredicate, listWidth } = useSelectContext();
594
598
  const { handleOpenChange } = inject(CustomSelectContextKey);
595
599
  const menuRef = shallowRef(null);
596
600
  const listRef = shallowRef(null);
@@ -758,6 +762,10 @@ const CustomSelectMenu = defineComponent({
758
762
  // On mount behavior
759
763
  onMounted(() => {
760
764
  syncActiveDescendant();
765
+ // A long list has a search field: the menu keeps the width of all its options as the results narrow.
766
+ if (searchable.value && listWidth.value === "auto" && menuRef.value) {
767
+ menuRef.value.style.minWidth = `${menuRef.value.offsetWidth}px`;
768
+ }
761
769
  // Like React's mount effect, the scroll target is the highlight at mount
762
770
  const initialHighlightedValue = highlightedValue.value;
763
771
  // Ensure initial highlighted option is in view