Skip to content

🥣 Cereal-ize JSON data into literally-typed constants, enums, & options in Nuxt.

License

Notifications You must be signed in to change notification settings

zoobzio/nuxt-cereal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nuxt-cereal

🥣 Cereal-ize JSON data into literally-typed constants, enums, & options in Nuxt.

✨  Release Notes

Configuration

  1. Install the module
pnpm add nuxt-cereal
  1. Create a config
// ~/ceral.config.ts
import { defineCerealConfig } from "nuxt-cereal/config";

export default defineCerealConfig({
  constants: {
    foo: "an example string",
  },
  enums: {
    bar: ["primary", "secondary", "tertiary"],
  },
  options: {
    baz: [
      { key: 1, label: "One" },
      { key: 2, label: "Two" },
    ],
  },
});
  1. Activate the module
// ~/nuxt.config.ts
import cereal from "./cereal.config";

export default defineNuxtConfig({
  modules: ["nuxt-cereal"],
  cereal,
});
  1. Eat some cereal, you are done!

Features

Define a JSON config object for:

  • constants A key/value collection of static strings & numbers
  • enums A key/value collection of static string arrays & number arrays
  • options A key/value collection of static option arrays w/ key & label properties

The config object is "cereal-ized" into read-only literals & implemented in Nuxt using a set of utility types/composables.

Types

Type templates are created using the JSON definitions & are automatically available in composables/components:

Type Description
ConstantTemplate Template constants value type (string or number)
Constant String-literal keys of the constants cereal config
ConstantValue<C extends Constant> Literal value of the provided constants config key
EnumTemplate Template enums value type (string[] or number[])
Enum String-literal keys of the enums cereal config
EnumValue<E extends Enum> Literal values of the provided enums config key
EnumValueItem<E extends Enum> Template values of the provided enums config key
OptionTemplate Template options value type (key & label props)
Option String-literal keys of the options cereal config
OptionValue<O extends Option> Literal values of the provided options config key
OptionValueItem<O extends Option> Template values of the provided options config key

Example

These utility types can be useful when creating components. Let's say we have a button component that has a variant property that can be set to either filled, outlined, or plain. We can configure that option as an enum and use the helper types to define our component properties:

// ~/cereal.config.ts
export default defineCerealConfig({
  enums: {
    buttonVariant: ["filled", "outlined", "plain"],
  },
});
<script setup lang="ts">
// ~/components/Button.vue
defineProps<{
  variant: EnumValue<"buttonVariant">; // a string-literal type of the options in our config
}>();
</script>

<template>
  <button :data-variant="variant">
    <slot />
  </button>
</template>

Functions

Type-safe utility functions that enable access to the configuration literal values are automatically imported in any component/composable:

Function Description
isConstant(key) Check if a provided string is a constants key & cast to Constant if valid
useConstant(key) Grab the literal value represented by the provided constants key
useConstantsConfig() Grab the entire constants configuration as an object literal
useConstantsKeys() Grab an array ofavailable constants configuration keys
isEnum(key) Check if a provided string is a enums key & cast to Enum if valid
useEnum(key) Grab the literal value represented by the provided enums key
useEnumsConfig() Grab the entire enums configuration as an object literal
useEnumsKeys() Grab an array ofavailable enums configuration keys
isOption(key) Check if a provided string is a options key & cast to Option if valid
useOption(key) Grab the literal value represented by the provided options key
useOptionsConfig() Grab the entire options configuration as an object literal
useOptionsKeys() Grab an array ofavailable options configuration keys

Example

These functions can be leveraged w/ generics to extend the power of our components even further. Imagine we have a pre-defined set of dropdowns needed for a form. We can quickly build a component that uses our cereal-ized data to provide a type-safe selector that only needs a key to get started:

// ~/cereal.config.ts
export default defineCerealConfig({
  options: {
    breakfast: [
      { key: "cereal", label: "Cereal" },
      { key: "pancakes", label: "Pancakes" },
      { key: "eggs", label: "Eggs" },
    ],
    lunch: [
      { key: "sandwhich", label: "Sandwhich" },
      { key: "soup", label: "Soup" },
      { key: "salad", label: "Salad" },
    ],
    dinner: [
      { key: "steak", label: "Steak" },
      { key: "lobster", label: "Lobster" },
      { key: "risotto", label: "Risotto" },
    ],
  },
});
<script setup lang="ts" generic="O extends Option">
// ~/components/Select.vue
const props = defineProps<{
  option: O; // "breakfast" | "lunch" | "dinner"
  modelValue?: OptionValueItem<O>["key"]; // if "breakfast" is the option, allowed values are "cereal" | "pancakes" | "eggs"
}>();

const emits = defineEmits<{
  "update:modelValue": [OptionValueItem<O>];
}>();

const options = useOption(props.option);
const modelValue = useVModel(props, "modelValue", emits, { passive: true }); // https://vueuse.org/core/useVModel/#usevmodel
</script>

<template>
  <select v-model="modelValue">
    <option v-for="o in options" :key="o.key" :value="o.key">
      {{ o.label }}
    </option>
  </select>
</template>