Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
feat(c-radio): create component
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerAPfledderer committed May 16, 2023
1 parent 1178174 commit 9613902
Show file tree
Hide file tree
Showing 18 changed files with 948 additions and 706 deletions.
14 changes: 14 additions & 0 deletions packages/c-radio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# `@chakra-ui/c-radio`

Radios are used when only one choice may be selected in a series of options

## Installation

```sh
# with pnpm
pnpm add @chakra-ui/c-radio
# or with Yarn
yarn i @chakra-ui/c-radio
# or with npm
npm i @chakra-ui/c-radio
```
21 changes: 21 additions & 0 deletions packages/c-radio/examples/controlled.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { ref } from "vue"
import { CVStack } from "../../layout/index"
import { CRadio, CRadioGroup } from "../index"
import { RadioGroupContext } from "../src/radio-context"
const selectedVal = ref("")
const radioGroupRef = ref<RadioGroupContext>()
</script>
<template>
<c-radio-group ref="radioGroupRef" v-model="selectedVal" v-slot="{ value }">
<div>Current Value: {{ value }}</div>
<c-v-stack>
<c-radio value="opt-1">Option 1</c-radio>
<c-radio value="opt-2">Option 2</c-radio>
<c-radio value="opt-3">Option 3</c-radio>
</c-v-stack>
</c-radio-group>
<button @click="() => radioGroupRef?.clearValue()">Clear</button>
</template>
3 changes: 3 additions & 0 deletions packages/c-radio/examples/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * as ControlledCRadio from "./controlled.vue"
export * as StateVariantsCRadio from "./state-variants.vue"
export * as WithSimpleGridCRadio from "./with-simple-grid.vue"
13 changes: 13 additions & 0 deletions packages/c-radio/examples/state-variants.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import { CVStack } from "../../layout/index"
import { CRadio, CRadioGroup } from "../index"
</script>
<template>
<c-radio-group value="1">
<c-v-stack>
<c-radio value="hello">Hello</c-radio>
<c-radio value="disabled" disabled>I'm disabled</c-radio>
<c-radio value="readonly" read-only>I can only be read</c-radio>
</c-v-stack>
</c-radio-group>
</template>
14 changes: 14 additions & 0 deletions packages/c-radio/examples/with-simple-grid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
import { CSimpleGrid } from "../../layout"
import { CRadio, CRadioGroup } from "../"
const range = Array.from(Array(10)).map((_, i) => i + 1)
</script>
<template>
<c-radio-group value="1">
<c-simple-grid as="div" :columns="2" :spacing="[2, 4, 6]">
<c-radio v-for="num in range" :key="num" :value="`Option ${num}`">{{
`Option ${num}`
}}</c-radio>
</c-simple-grid>
</c-radio-group>
</template>
1 change: 1 addition & 0 deletions packages/c-radio/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./src"
46 changes: 46 additions & 0 deletions packages/c-radio/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@chakra-ui/c-radio",
"description": "Chakra UI Vue | Radios are used when only one choice may be selected in a series of options component",
"version": "0.0.0-beta.0",
"author": "Jonathan Bakebwa <[email protected]>",
"homepage": "https://github.com/chakra-ui/chakra-ui-vue-next#readme",
"license": "MIT",
"main": "src/index.ts",
"clean-package": "../../clean-package.config.json",
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/chakra-ui/chakra-ui-vue-next.git"
},
"bugs": {
"url": "https://github.com/chakra-ui/chakra-ui-vue-next/issues"
},
"sideEffects": false,
"scripts": {
"clean": "rimraf dist .turbo",
"build": "tsup && pnpm build:types",
"build:fast": "tsup",
"build:types": "tsup src --dts-only",
"types:check": "tsc --noEmit",
"dev": "tsup --watch"
},
"dependencies": {
"@chakra-ui/vue-system": "workspace:*",
"@chakra-ui/vue-composables": "workspace:*",
"@chakra-ui/vue-utils": "workspace:*",
"@zag-js/radio-group": "0.7.0",
"@zag-js/vue": "0.7.0",
"@chakra-ui/styled-system": "2.9.0"
},
"devDependencies": {
"vue": "^3.2.37"
},
"peerDependencies": {
"vue": "^3.1.4"
},
"publishConfig": {
"access": "public"
}
}
72 changes: 72 additions & 0 deletions packages/c-radio/src/c-radio-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { h, PropType, defineComponent } from "vue"
import { UseRadioGroupProps, useRadioGroup } from "./use-radio-group"
import {
HTMLChakraProps,
ThemingProps,
chakra,
useMultiStyleConfig,
} from "@chakra-ui/vue-system"
import { RadioGroupProvider, RadioGroupStylesProvider } from "./radio-context"
import { useThemingProps, vueThemingProps } from "@chakra-ui/vue-utils"

export interface CRadioGroupProps
extends UseRadioGroupProps,
HTMLChakraProps<"div">,
Omit<ThemingProps<"Radio">, "orientation"> {}

export const CRadioGroup = defineComponent({
name: "CRadioGroup",
props: {
dir: {
type: String as PropType<CRadioGroupProps["dir"]>,
},
disabled: {
type: Boolean as PropType<CRadioGroupProps["disabled"]>,
},
form: {
type: String as PropType<CRadioGroupProps["form"]>,
},
getRootNode: {
type: Function as PropType<CRadioGroupProps["getRootNode"]>,
},
id: {
type: String as PropType<CRadioGroupProps["id"]>,
},
ids: {
type: Object as PropType<CRadioGroupProps["ids"]>,
},
name: {
type: String as PropType<CRadioGroupProps["name"]>,
},
modelValue: {
type: String as PropType<CRadioGroupProps["modelValue"]>,
},
orientation: {
type: String as PropType<CRadioGroupProps["orientation"]>,
},
readonly: {
type: Boolean as PropType<CRadioGroupProps["readOnly"]>,
},
...vueThemingProps,
},
emits: ["change", "update:modelValue"],
setup(props, { slots, attrs, expose }) {
const api = useRadioGroup(props)

const themeProps = useThemingProps(props)

const styles = useMultiStyleConfig("Radio", themeProps)

RadioGroupProvider(api)

RadioGroupStylesProvider(styles)

expose(api.value)

return () => (
<chakra.div __label="radio-group" {...api.value.rootProps} {...attrs}>
{slots.default?.(api.value)}
</chakra.div>
)
},
})
142 changes: 142 additions & 0 deletions packages/c-radio/src/c-radio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* Hey! Welcome to @chakra-ui/vue-next CRadio
*
* Radios are used when only one choice may be selected in a series of options
*
* @see Docs https://next.vue.chakra-ui.com/c-radio
* @see Source https://github.com/chakra-ui/chakra-ui-vue-next/blob/main/packages/c-radio/src/c-radio/c-radio.ts
* @see WAI-ARIA https://www.w3.org/TR/wai-aria-practices-1.2
*/

import {
computed,
defineComponent,
h,
InputHTMLAttributes,
isVNode,
mergeProps,
PropType,
reactive,
} from "vue"
import {
chakra,
HTMLChakraProps,
type ThemingProps,
type StyleResolverProps,
useMultiStyleConfig,
} from "@chakra-ui/vue-system"
import * as VS from "@chakra-ui/vue-system"
import { getValidChildren, SNAO, vueThemingProps } from "@chakra-ui/vue-utils"
import { RadioContext, useRadioGroupContext } from "./radio-context"

export interface CRadioProps
extends Omit<HTMLChakraProps<"label">, keyof RadioContext>,
ThemingProps<"Radio">,
RadioContext {
/**
* The spacing between the checkbox and its label text
* @default 0.5rem
* @type SystemProps["marginLeft"]
*/
spacing?: StyleResolverProps["marginLeft"]
/**
* Additional props to be forwarded to the `input` element
*/
inputProps?: InputHTMLAttributes
}

export const CRadio = defineComponent({
props: {
value: {
type: String as PropType<CRadioProps["value"]>,
required: true,
},
disabled: {
type: Boolean as PropType<CRadioProps["disabled"]>,
},
invalid: {
type: Boolean as PropType<CRadioProps["invalid"]>,
},
readOnly: {
type: Boolean as PropType<CRadioProps["readOnly"]>,
},
spacing: {
type: SNAO as PropType<CRadioProps["spacing"]>,
default: "0.5rem",
},
...vueThemingProps,
},
setup(props, { slots, attrs }) {
const groupApi = useRadioGroupContext()

const styleAttrs = computed(() => mergeProps(props, groupApi.value, attrs))

const styles = useMultiStyleConfig("Radio", styleAttrs)

const radioProps = reactive({
value: props.value,
disabled: props.disabled,
invalid: props.invalid,
readOnly: props.readOnly,
})

const inputProps = computed(() => {
const apiInputProps = groupApi.value.getRadioInputProps(radioProps)
const apiInputState = groupApi.value.getRadioState(radioProps)

return {
...apiInputProps,
// modelValue: apiInputState.isChecked,
}
})

const rootStyles = computed(() => ({
display: "inline-flex",
alignItems: "center",
verticalAlign: "top",
cursor: "pointer",
position: "relative",
...styles.value.container,
}))

const labelStyles = computed(() => ({
userSelect: "none",
marginStart: props.spacing,
...styles.value.label,
}))

const controlStyles = computed(() => ({
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
...styles.value.control,
}))

return () => (
<chakra.label
{...groupApi.value.getRadioProps(radioProps)}
__css={rootStyles.value}
{...attrs}
>
<chakra.input
__chakraIsRaw
__label="radio__input"
{...inputProps.value}
/>
<chakra.span
__label="radio__control"
{...groupApi.value.getRadioControlProps(radioProps)}
__css={controlStyles.value}
/>
<chakra.span
__label="radio__label"
{...groupApi.value.getRadioLabelProps(radioProps)}
__css={labelStyles.value}
>
{() => getValidChildren(slots)}
</chakra.span>
</chakra.label>
)
},
})
3 changes: 3 additions & 0 deletions packages/c-radio/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { CRadioGroup, type CRadioGroupProps } from "./c-radio-group"
export { CRadio, type CRadioProps } from "./c-radio"
export type { RadioGroupContext } from "./radio-context"
27 changes: 27 additions & 0 deletions packages/c-radio/src/radio-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as CSS from "csstype"
import * as radio from "@zag-js/radio-group"
import { createContext } from "@chakra-ui/vue-utils"
import type { UseRadioGroupReturn } from "./use-radio-group"
import { UnwrapRef } from "vue"
import { createStylesContext } from "@chakra-ui/vue-system"
import * as VS from "@chakra-ui/vue-system"

export type RadioContext = Parameters<
ReturnType<typeof radio.connect>["getRadioProps"]
>[0]

export const [RadioProvider, useRadioContext] = createContext<RadioContext>({
name: "CRadioContext",
strict: true,
})

export type RadioGroupContext = UnwrapRef<UseRadioGroupReturn>

export const [RadioGroupProvider, useRadioGroupContext] =
createContext<UseRadioGroupReturn>({
name: "CRadioGroupContext",
strict: true,
})

export const [RadioGroupStylesProvider, useRadioGroupStyles] =
createStylesContext("CRadioGroup")
Loading

0 comments on commit 9613902

Please sign in to comment.