bonkers-ui 1.0.23 → 1.0.25

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.
@@ -0,0 +1,32 @@
1
+ import { create } from '@storybook/theming/create';
2
+
3
+ export default create({
4
+ base: 'light',
5
+ colorPrimary: '#56c55d',
6
+ colorSecondary: 'rgba(86, 197, 93, 0.9)',
7
+
8
+ // UI
9
+ appBg: 'white',
10
+ appContentBg: 'white',
11
+ appBorderColor: 'silver',
12
+ appBorderRadius: 4,
13
+
14
+ // Text colors
15
+ textColor: 'black',
16
+ textInverseColor: 'rgba(255,255,255,0.9)',
17
+
18
+ // Toolbar default and active colors
19
+ barTextColor: 'silver',
20
+ barSelectedColor: '#56c55d',
21
+ barBg: 'white',
22
+
23
+ // Form colors
24
+ inputBg: 'white',
25
+ inputBorder: 'silver',
26
+ inputTextColor: 'black',
27
+ inputBorderRadius: 4,
28
+
29
+ brandTitle: 'Bonkers-UI Design System',
30
+ brandUrl: 'https://github.com/bonkers-ie/bonkers-ui',
31
+ brandImage: 'https://web-assets.bonkers.ie/packs/static/logo/bonkers_logo-279f0cff5a9b71e3059a.svg',
32
+ });
@@ -0,0 +1,7 @@
1
+
2
+ import { addons } from '@storybook/addons';
3
+ import BonkersTheme from './BonkersTheme';
4
+
5
+ addons.setConfig({
6
+ theme: BonkersTheme,
7
+ });
@@ -6,10 +6,10 @@ import { library } from '@fortawesome/fontawesome-svg-core';
6
6
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
7
7
 
8
8
  /* import specific icons */
9
- import { faFaceSmile } from '@fortawesome/free-regular-svg-icons';
9
+ import { faFaceSmile, faCircleCheck } from '@fortawesome/free-regular-svg-icons';
10
10
 
11
11
  /* add icons to the library */
12
- library.add(faFaceSmile);
12
+ library.add(faFaceSmile, faCircleCheck);
13
13
 
14
14
  import '../src/main.css';
15
15
 
@@ -19,6 +19,24 @@ export const parameters = {
19
19
  darkMode: false,
20
20
  stylePreview: true,
21
21
  actions: {argTypesRegex: "^on[A-Z].*"},
22
+ backgrounds: {
23
+ default: "Bonkers",
24
+ values: [
25
+ {
26
+ name: "Bonkers",
27
+ value: "url(https://web-assets.bonkers.ie/maverick/img/about.0ed347c.png)",
28
+ },
29
+ {
30
+ name: "Light",
31
+ value: "#ffffff"
32
+ },
33
+ {
34
+ name: "Dark",
35
+ value: "#202124"
36
+ }
37
+ ],
38
+ },
39
+ layout: "padded",
22
40
  controls: {
23
41
  matchers: {
24
42
  color: /(background|color)$/i,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bonkers-ui",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "storybook": "start-storybook -p 6006",
@@ -19,6 +19,8 @@
19
19
  "@fortawesome/free-regular-svg-icons": "^6.2.0",
20
20
  "@fortawesome/free-solid-svg-icons": "^6.2.0",
21
21
  "@fortawesome/vue-fontawesome": "^3.0.1",
22
+ "@vueuse/components": "^9.4.0",
23
+ "@vueuse/core": "^9.4.0",
22
24
  "husky": "4.3.8",
23
25
  "vue": "^3.2.41"
24
26
  },
@@ -1,4 +1,6 @@
1
1
  {
2
2
  "md": "var(--shadow-size-md)",
3
- "border-primary": "var(--shadow-border-primary)"
3
+ "border-primary": "var(--shadow-border-primary)",
4
+ "border-selected": "var(--shadow-border-selected)",
5
+ "selected-shadow": "var(--shadow-selected-shadow)"
4
6
  }
@@ -3,6 +3,8 @@
3
3
  /* shadow sizes */
4
4
  --shadow-size-md: 0 2px 4px 0 rgb(180 184 205 / 50%);
5
5
  --shadow-border-primary: 0 0 0 4px rgb(69 158 74 / 50%);
6
+ --shadow-border-selected: 0 0 0 4px rgb(69 158 74 / 100%);
7
+ --shadow-selected-shadow: 0 0 0 4px var(--color-primary-500);
6
8
  --shadow-border-secondary: 0 0 0 4px rgb(223 225 233 / 50%);
7
9
  }
8
10
  }
@@ -0,0 +1 @@
1
+ export { default } from "./ui-backdrop.vue";
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <transition-group
3
+ name="fade"
4
+ enter-active-class="transition-opacity duration-300"
5
+ leave-active-class="transition-opacity duration-300 opacity-0"
6
+ enter-from-class="opacity-0"
7
+ leave-to-class="opacity-0"
8
+ >
9
+ <div
10
+ v-if="visible"
11
+ class="
12
+ backdrop-color
13
+ fixed
14
+ backdrop-blur-sm
15
+ transition-all
16
+ inset-0
17
+ z-0
18
+ "
19
+ />
20
+
21
+ <slot />
22
+ </transition-group>
23
+ </template>
24
+
25
+ <script lang="ts" setup>
26
+
27
+ withDefaults(
28
+ defineProps<{
29
+ visible?: boolean;
30
+ }>(),
31
+ {
32
+ visible: true,
33
+ }
34
+ );
35
+
36
+ </script>
37
+
38
+ <style lang="css" scoped>
39
+ .backdrop-color {
40
+ background-color: rgb(0 0 0 / 50%);
41
+ }
42
+ </style>
@@ -54,7 +54,7 @@ const Template: Story<TComponentProps> = (args) => ({
54
54
  return { args, ESize };
55
55
  },
56
56
  // And then the `args` are bound to your component with `v-bind="args"`
57
- template: `
57
+ template: /*html*/`
58
58
  <ui-button :kind="args.kind"
59
59
  :size="args.size"
60
60
  :fullWidth="args.fullWidth"
@@ -82,7 +82,7 @@ const TemplateAll: Story<TComponentProps> = () => ({
82
82
  return { EButtonSizes, EButtonTypes };
83
83
  },
84
84
 
85
- template: `
85
+ template: /*html*/`
86
86
  <div :style="{
87
87
  display: 'flex',
88
88
  flexWrap: 'wrap'
@@ -1,2 +1,2 @@
1
1
  export { default } from "./ui-icon-wrapper.vue";
2
- export { EIconWrapperTypes } from "./_typings";
2
+ export { EIconWrapperTypes, EIconWrapperSizes } from "./_typings";
@@ -20,13 +20,15 @@
20
20
  <slot name="prefix-icon" />
21
21
 
22
22
  <input
23
- v-model="inputModel"
23
+ :value="modelValue"
24
+ :pattern="pattern"
24
25
  class="bg-transparent border-0 outline-none w-full placeholder:text-secondary-alt placeholder:italic"
25
26
  :type="type || 'text'"
26
27
  :placeholder="placeholder"
27
- :pattern="pattern"
28
28
  :maxlength="maxlength"
29
29
  :minlength="minlength"
30
+ @input="$emit('update:modelValue', ($event.target as HTMLTextAreaElement)?.value)"
31
+ @focus="focusHandler"
30
32
  >
31
33
 
32
34
  <slot name="postfix-icon" />
@@ -42,11 +44,10 @@
42
44
  </template>
43
45
 
44
46
  <script lang="ts" setup>
45
- import { computed } from "vue";
46
47
  import { EInputKinds, EInputType } from "./_typings";
47
48
  import UiTypography, { ETypographySizes, ETextWeight } from "../ui-typography";
48
49
 
49
- const props = defineProps<{
50
+ withDefaults(defineProps<{
50
51
  placeholder?: string;
51
52
  modelValue: string;
52
53
  disabled?: boolean;
@@ -57,17 +58,11 @@
57
58
  pattern?: string;
58
59
  maxlength?: string;
59
60
  minlength?: string;
60
- }>();
61
-
62
- const emit = defineEmits(["update:modelValue"]);
63
-
64
- const inputModel = computed({
65
- get() {
66
- return props.modelValue;
67
- },
68
- set(value) {
69
- emit("update:modelValue", value);
70
- }
61
+ focusHandler?: (e:FocusEvent) => void;
62
+ }>(), {
63
+ modelValue: ""
71
64
  });
72
65
 
66
+ defineEmits(["update:modelValue"]);
67
+
73
68
  </script>
@@ -42,18 +42,19 @@ const Template: Story<TComponentProps> = (args) => ({
42
42
  },
43
43
  template:/*html*/`
44
44
  <ul>
45
- <ui-list-item :icon="['far', 'face-smile']" title="title only" :kind="args.kind" :size="args.size">
45
+ <ui-list-item v-bind="args" :icon="['far', 'face-smile']" title="title only">
46
46
  {{args.slot}}
47
47
  </ui-list-item>
48
48
 
49
- <ui-list-item :icon="['far', 'face-smile']" :kind="args.kind" :size="args.size">
49
+ <ui-list-item v-bind="args" :icon="['far', 'face-smile']">
50
50
  text only
51
51
  </ui-list-item>
52
52
 
53
- <ui-list-item v-for= "item in 5" :key="item" :icon="['far', 'face-smile']" :title="args.title" :kind="args.kind" :size="args.size">
53
+ <ui-list-item v-bind="args" v-for= "item in 5" :key="item" :icon="['far', 'face-smile']">
54
54
  {{ args.title }}
55
55
  </ui-list-item>
56
- <ui-list-item class="compact-list-item" :icon="['far', 'face-smile']" :size="args.size" :title="args.title">
56
+
57
+ <ui-list-item v-bind="args" class="compact-list-item" :icon="['far', 'face-smile']" />
57
58
  </ul>
58
59
  `,
59
60
  });
@@ -11,14 +11,14 @@
11
11
  v-if="kind===EListItemTypes.PROGRESS"
12
12
  class="ui-list-item__line bg-primary-300 h-full absolute w-xxs left-xs -translate-x-2/4 top-sm group-last:hidden"
13
13
  />
14
-
14
+
15
15
  <ui-icon
16
16
  v-if="icon"
17
- :kind="pickKind"
18
17
  class="bg-white text-primary"
19
18
  :icon-name="icon"
20
19
  :size="ESize.SM"
21
20
  />
21
+
22
22
  <div>
23
23
  <ui-typography
24
24
  v-if="title"
@@ -32,30 +32,21 @@
32
32
  </template>
33
33
 
34
34
  <script lang="ts" setup>
35
- import { computed } from "vue";
36
35
  import UiIcon, { type TIconName } from "../ui-icon";
37
36
  import UiTypography, { ETextWeight } from "../ui-typography";
38
37
  import { ESize } from "../../_types/sizing";
39
- import { EListItemTypes } from "./_types";
40
- import { EListItemSizes } from "./_types";
38
+ import { EListItemTypes, EListItemSizes } from "./_types";
41
39
 
42
- const props = withDefaults(defineProps<{
43
- icon: TIconName
40
+ withDefaults(defineProps<{
41
+ icon?: TIconName
44
42
  title?: string
45
43
  kind?: EListItemTypes
46
- size: EListItemSizes
44
+ size?: EListItemSizes
47
45
  }>(), {
48
46
  kind: EListItemTypes.DEFAULT,
49
47
  size: EListItemSizes.COMPACT,
50
- title: ""
51
- });
52
-
53
- const pickKind = computed(()=>{
54
- switch(props.kind){
55
- case EListItemTypes.DEFAULT: return EListItemTypes.DEFAULT;
56
- case EListItemTypes.PROGRESS: return EListItemTypes.PROGRESS;
57
- default: return EListItemTypes.DEFAULT;
58
- }
48
+ title: "",
49
+ icon: undefined
59
50
  });
60
51
 
61
52
  </script>
@@ -0,0 +1,6 @@
1
+ export enum EModalSizes {
2
+ SM = "sm",
3
+ MD = "md",
4
+ LG = "lg",
5
+ RESPONSIVE = "responsive",
6
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from "./ui-modal.vue";
2
+ export { EModalSizes } from "./_typings";
@@ -0,0 +1,103 @@
1
+ import { ref } from "vue";
2
+ import type { Story } from "@storybook/vue3";
3
+ import UiModal from "./ui-modal.vue";
4
+ import UiButton from "../ui-button";
5
+ import UiBackdrop from "../ui-backdrop";
6
+ import UiIcon from "../ui-icon";
7
+ import UiTypography from "../ui-typography";
8
+ import { ESize } from "../../_types/sizing";
9
+ import { EModalSizes } from "./_typings";
10
+
11
+ export default {
12
+ title: "Components/ui-modal",
13
+ component: UiModal,
14
+ argTypes: {
15
+ title: {
16
+ control: { type: "text" },
17
+ description: "The modal title text",
18
+ },
19
+ modalSize: {
20
+ control: { type: "select" },
21
+ options: Object.values(EModalSizes),
22
+ description: "The modal kinds",
23
+ },
24
+ modalVisible: {
25
+ control: { type: "boolean" },
26
+ description: "Control Modal Visibility",
27
+ },
28
+
29
+ },
30
+ args: {
31
+ title: "Password Updated",
32
+ body: "You can now use your new security info to sign in to your account",
33
+ modalSize: ESize.SM,
34
+ }
35
+ };
36
+
37
+ type TComponentProps = InstanceType<typeof UiModal>["$props"];
38
+
39
+ const Template: Story<TComponentProps> = (args) => ({
40
+ components: { UiModal, UiBackdrop, UiButton, UiIcon, UiTypography },
41
+ setup() {
42
+ const isVisible = ref(false);
43
+
44
+ const showModal = () => {
45
+ isVisible.value = true;
46
+ };
47
+
48
+ const closeModal = () => {
49
+ isVisible.value = false;
50
+ };
51
+
52
+ return { args, showModal, closeModal, isVisible, ESize };
53
+ },
54
+ template:/*html*/`
55
+ <transition
56
+ name="ui-modal"
57
+ mode="out-in"
58
+ appear
59
+ enter-active-class="transition delay-100"
60
+ enter-from-class="opacity-0 translate-y-1/4"
61
+ enter-to-class="opacity-100 translate-y-0"
62
+ leave-active-class="transition"
63
+ leave-to-class="opacity-0 translate-y-1/4"
64
+ leave-from-class="opacity-100 translate-y-0"
65
+ >
66
+ <ui-modal
67
+ v-if="isVisible"
68
+ :title="args.title"
69
+ :modalSize="args.modalSize"
70
+ :closeModal="closeModal"
71
+ >
72
+ <template #icon>
73
+ <ui-icon class="text-primary" :icon-name="['far', 'circle-check']" :size=ESize.XL />
74
+ </template>
75
+ <template #title>
76
+ <ui-typography class="text-2xl font-bold">{{ args.title }}</ui-typography>
77
+ </template>
78
+
79
+ <template #default >
80
+ {{args.body}}
81
+ </template>
82
+ <template #footer>
83
+ <ui-button
84
+ fullWidth
85
+ @click="closeModal"
86
+ >
87
+ Ok
88
+ </ui-button>
89
+ </template>
90
+ </ui-modal>
91
+ </transition>
92
+
93
+ <ui-backdrop v-if="isVisible" />
94
+
95
+ <div class="absolute" style="top: calc(50vh - 2rem); left: calc(50vw - 4rem)">
96
+ <ui-button @click="showModal">
97
+ Toggle Modal
98
+ </ui-button>
99
+ </div>
100
+ `
101
+ });
102
+
103
+ export const Default = Template.bind({});
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <div
3
+ v-on-click-outside="closeModal"
4
+ class="
5
+ ui-modal
6
+ absolute
7
+ m-auto
8
+ flex flex-col
9
+ items-center
10
+ z-10
11
+ opacity-0
12
+ inset-0
13
+ rounded-2xl
14
+ shadow-md
15
+ p-md
16
+ bg-white
17
+ overflow-y-scroll
18
+ "
19
+ :class="[
20
+ modalSize === EModalSizes.SM &&'h-fit max-h-[24rem] max-w-[24rem]',
21
+ modalSize === EModalSizes.MD &&'h-fit max-h-[32rem] max-w-[32rem]',
22
+ modalSize === EModalSizes.LG &&'h-fit max-h-[40rem] max-w-[40rem]',
23
+ modalSize === EModalSizes.RESPONSIVE && 'h-5/6 w-11/12',
24
+ ]"
25
+ >
26
+ <div
27
+ class="mt-md mb-sm"
28
+ >
29
+ <slot name="icon" />
30
+ </div>
31
+ <ui-typography
32
+ v-if="title"
33
+ class="my-md"
34
+ :weight="ETextWeight.BOLD"
35
+ :align="ETextAlign.CENTER"
36
+ :size="ETypographySizes.LG"
37
+ >
38
+ {{ title }}
39
+ </ui-typography>
40
+ <ui-typography
41
+ :weight="ETextWeight.REGULAR"
42
+ :align="ETextAlign.CENTER"
43
+ line-height
44
+ class="text-secondary mb-md"
45
+ >
46
+ <slot />
47
+ </ui-typography>
48
+
49
+ <div class="w-full mt-auto">
50
+ <slot name="footer" />
51
+ </div>
52
+ </div>
53
+ </template>
54
+ <script lang="ts" setup>
55
+ import { vOnClickOutside } from "@vueuse/components";
56
+ import { ETypographySizes } from "../ui-typography/";
57
+ import UiTypography, { ETextWeight, ETextAlign } from "../ui-typography";
58
+ import { EModalSizes } from "./_typings";
59
+
60
+ withDefaults(
61
+ defineProps<{
62
+ title: string;
63
+ modalSize?: EModalSizes;
64
+ closeModal: () => void;
65
+ }>(),
66
+ {
67
+ modalSize: EModalSizes.SM,
68
+ }
69
+ );
70
+
71
+ </script>
@@ -7,23 +7,42 @@ export default {
7
7
  title: "Components/ui-radio-fancy",
8
8
  component: UiRadioFancy,
9
9
  // More on argTypes: https://storybook.js.org/docs/vue/api/argtypes
10
- argTypes: {},
11
- args: {},
10
+ argTypes: {
11
+ invertOrder: {
12
+ control: { type: "boolean" },
13
+ description: "The Element order",
14
+ },
15
+ disabled: {
16
+ control: { type: "boolean" },
17
+ description: "The full width size",
18
+ },
19
+ },
20
+ args: {
21
+ slot: "Description",
22
+ invertOrder: false,
23
+ disabled: false
24
+ },
12
25
  };
13
26
 
14
27
  type TComponentProps = InstanceType<typeof UiRadioFancy>["$props"];
15
28
 
16
- const Template: Story<TComponentProps> = () => ({
29
+ const Template: Story<TComponentProps> = (args) => ({
17
30
  components: { UiRadioFancy },
18
31
  setup() {
19
32
  const modelValue = ref("1");
20
33
 
21
- return { modelValue, EIconType };
34
+ return { modelValue, EIconType, args };
22
35
  },
23
36
  template: /*html*/`
24
37
  <div class="grid gap-sm" :style="{'grid-template-columns': 'repeat(auto-fit, minmax(160px, 1fr))'}">
25
- <ui-radio-fancy v-for="item in 3" :key="item" :value="String(item)" v-model="modelValue" name="radio" title="title" :icon-name="[EIconType.FAR, 'face-smile']">
26
- {{args.slot}}
38
+ <ui-radio-fancy v-bind="args" :key="key" value="1" v-model="modelValue" name="radio" :icon-name="[EIconType.FAR, 'face-smile']">
39
+ Banana
40
+ </ui-radio-fancy>
41
+ <ui-radio-fancy v-bind="args" :key="key" value="2" v-model="modelValue" name="radio" :icon-name="[EIconType.FAR, 'face-smile']">
42
+ Apple
43
+ </ui-radio-fancy>
44
+ <ui-radio-fancy v-bind="args" :key="key" value="3" v-model="modelValue" name="radio" :icon-name="[EIconType.FAR, 'face-smile']">
45
+ Orange
27
46
  </ui-radio-fancy>
28
47
  </div>
29
48
  `,
@@ -1,31 +1,55 @@
1
1
  <template>
2
2
  <label
3
- class="ui-radio-item block p-sm border rounded-2xl hover:border-primary cursor-pointer bg-white"
4
- :class="[
5
- isActive ? 'border-primary pointer-events-none':'border-secondary-alt',
6
- ]"
3
+ class="ui-radio-fancy"
4
+ :class="disabled && 'pointer-events-none opacity-50'"
7
5
  >
8
6
  <input
9
7
  v-model="radioModel"
10
8
  type="radio"
11
9
  :name="name"
12
10
  :value="value"
13
- class="appearance-none absolute"
11
+ class="peer group fixed w-0"
12
+ :class="disabled && 'pointer-events-none opacity-50'"
14
13
  >
15
-
16
- <ui-icon
17
- :icon-name="iconName"
18
- :size="ESize.MD"
19
- class="mb-md"
20
- :class="isActive && 'text-primary'"
21
- />
22
- <ui-typography
23
- :size="ETypographySizes.SM"
24
- :kind="EColors.SECONDARY"
25
- :weight="ETextWeight.SEMI_BOLD"
14
+ <div
15
+ class="
16
+ ui-radio-fancy__content
17
+ box-border
18
+ w-full
19
+ py-sm px-sm
20
+ border
21
+ border-secondary-alt-500
22
+ hover:border-secondary-alt-700
23
+ cursor-pointer
24
+ rounded-xl
25
+ active:border-sm
26
+ active:bg-secondary-alt-200
27
+ peer-checked:active:outline-4
28
+ peer-checked:active:outline
29
+ peer-checked:active:outline-offset-4
30
+ peer-checked:border-transparent
31
+ active:outline
32
+ active:outline-4
33
+ active:outline-primary
34
+ active:border-secondary-alt
35
+ peer-checked:hover:shadow-border-selected
36
+ peer-checked:shadow-selected-shadow"
37
+ :class="disabled && 'pointer-events-none opacity-50'"
26
38
  >
27
- {{ title }}
28
- </ui-typography>
39
+ <ui-icon
40
+ :icon-name="iconName"
41
+ :size="ESize.MD"
42
+ class="mb-md group-checked:text-primary-500"
43
+ :class="value === modelValue && 'text-primary'"
44
+ />
45
+ <ui-typography
46
+ :size="ETypographySizes.SM"
47
+ :kind="EColors.SECONDARY"
48
+ :weight="ETextWeight.SEMI_BOLD"
49
+ >
50
+ <slot />
51
+ </ui-typography>
52
+ </div>
29
53
  </label>
30
54
  </template>
31
55
 
@@ -35,17 +59,15 @@
35
59
  import UiIcon, { type TIconName } from "../ui-icon";
36
60
  import { ESize } from "../../_types/sizing";
37
61
  import { EColors } from "../../_types/colors";
38
-
39
62
  const props = defineProps<{
40
63
  modelValue: string;
41
64
  name: string;
42
65
  value: string | number;
43
- title: string;
66
+ id: string;
44
67
  iconName: TIconName;
68
+ disabled?: boolean;
45
69
  }>();
46
-
47
70
  const emit = defineEmits(["update:modelValue"]);
48
-
49
71
  const radioModel = computed({
50
72
  get() {
51
73
  return props.modelValue;
@@ -54,6 +76,4 @@
54
76
  emit("update:modelValue", value);
55
77
  }
56
78
  });
57
-
58
- const isActive = computed(()=>props.modelValue === props.value);
59
79
  </script>