@avakhula/ui 0.1.13 → 0.1.15

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.
Files changed (116) hide show
  1. package/.prettierrc.json +0 -0
  2. package/.storybook/intelliboardTheme.js +0 -0
  3. package/.storybook/manager.js +0 -0
  4. package/.storybook/scss-loader.scss +0 -0
  5. package/.storybook/withSource.js +0 -0
  6. package/README.md +0 -0
  7. package/dist/index.js +9028 -7513
  8. package/dist/index.umd.cjs +76 -73
  9. package/dist/style.css +1 -1
  10. package/index.html +0 -0
  11. package/package.json +4 -3
  12. package/src/App.vue +5 -128
  13. package/src/EventEmmiter.js +0 -0
  14. package/src/assets/scss/mixins/dropdown-list-item.scss +13 -1
  15. package/src/assets/scss/mixins.scss +0 -0
  16. package/src/assets/scss/reset.scss +0 -0
  17. package/src/assets/scss/style.scss +0 -0
  18. package/src/assets/scss/typography.scss +0 -0
  19. package/src/components/Alert/Alert.vue +5 -0
  20. package/src/components/Alert/alert.scss +6 -1
  21. package/src/components/Avatar/Avatar.stories.js +5 -1
  22. package/src/components/Avatar/Avatar.vue +25 -2
  23. package/src/components/Avatar/constants.js +6 -0
  24. package/src/components/Badge/Badge.stories.js +0 -0
  25. package/src/components/Breadcrumbs/Breadcrumbs.vue +17 -7
  26. package/src/components/Button/Button.stories.js +0 -0
  27. package/src/components/Button/Button.vue +19 -3
  28. package/src/components/Button/button.scss +5 -0
  29. package/src/components/Button/constants.js +0 -0
  30. package/src/components/ButtonGroup/ButtonGroup.vue +0 -0
  31. package/src/components/Chips/Chips.stories.js +30 -0
  32. package/src/components/Chips/Chips.vue +125 -0
  33. package/src/components/Dropdown/Dropdown.spec.js +0 -0
  34. package/src/components/Dropdown/DropdownDivider.vue +0 -0
  35. package/src/components/Dropdown/DropdownItem.vue +26 -4
  36. package/src/components/Dropdown/DropdownList.vue +0 -0
  37. package/src/components/Dropdown/constants.js +0 -0
  38. package/src/components/Form/CharactersCount.vue +10 -7
  39. package/src/components/Form/Checkbox/Checkbox.vue +25 -11
  40. package/src/components/Form/CheckboxGroup/CheckboxGroup.vue +15 -0
  41. package/src/components/Form/CheckboxGroup/readme.mdx +2 -0
  42. package/src/components/Form/DatePicker/DatePicker.scss +352 -261
  43. package/src/components/Form/DatePicker/DatePicker.vue +72 -17
  44. package/src/components/Form/DatePicker/Icons/chevron-back.js +0 -0
  45. package/src/components/Form/DatePicker/Icons/chevron-forward.js +0 -0
  46. package/src/components/Form/FormGroup/FormGroup.stories.js +0 -0
  47. package/src/components/Form/FormGroup/FormGroup.vue +3 -3
  48. package/src/components/Form/FormGroup/FormGroupSet.stories.js +0 -0
  49. package/src/components/Form/FormGroup/FormGroupSet.vue +0 -0
  50. package/src/components/Form/Input/Input.vue +116 -13
  51. package/src/components/Form/Input/input.scss +61 -2
  52. package/src/components/Form/Label/Label.vue +22 -10
  53. package/src/components/Form/PhoneInput/PhoneInput.vue +26 -12
  54. package/src/components/Form/PhoneInput/phoneInput.scss +38 -6
  55. package/src/components/Form/Radio/Radio.vue +16 -44
  56. package/src/components/Form/Radio/radio.scss +5 -2
  57. package/src/components/Form/TextEditor/TextEditor.vue +117 -22
  58. package/src/components/Form/TextEditor/icons/svg/chevron-down.svg +0 -0
  59. package/src/components/Form/TextEditor/icons/toolbarIcons.js +0 -0
  60. package/src/components/Form/TextEditor/plugins/alphabetList.js +0 -0
  61. package/src/components/Form/TextEditor/textEditor.scss +56 -32
  62. package/src/components/Form/Textarea/Textarea.spec.js +0 -0
  63. package/src/components/Form/Textarea/Textarea.vue +19 -6
  64. package/src/components/Form/Textarea/textarea.scss +30 -2
  65. package/src/components/Icon.vue +0 -0
  66. package/src/components/IconButton/IconButton.scss +11 -0
  67. package/src/components/IconButton/IconButton.stories.js +0 -0
  68. package/src/components/IconButton/IconButton.vue +6 -9
  69. package/src/components/IconButton/constants.js +0 -0
  70. package/src/components/Modal/Modal.vue +42 -9
  71. package/src/components/Pagination/LimitSelector.vue +5 -0
  72. package/src/components/Pagination/Pagination.stories.js +0 -0
  73. package/src/components/Pagination/Pagination.vue +9 -2
  74. package/src/components/Panel/Panel.vue +87 -6
  75. package/src/components/Popover/Popover.stories.js +0 -0
  76. package/src/components/Popover/Popover.vue +47 -19
  77. package/src/components/Popover/popover.scss +27 -7
  78. package/src/components/ProgressBar/ProgressBar.stories.js +0 -0
  79. package/src/components/Sorting/Sorting.vue +24 -26
  80. package/src/components/Sorting/constants.js +0 -0
  81. package/src/components/SplitButton/SplitButton.vue +51 -8
  82. package/src/components/SplitButton/SplitButtonItem.vue +13 -1
  83. package/src/components/SplitButton/constants.js +0 -0
  84. package/src/components/Table/Cells/Cell.vue +0 -0
  85. package/src/components/Table/Cells/CheckboxCell.vue +0 -0
  86. package/src/components/Table/Row.vue +0 -0
  87. package/src/components/Table/Table.stories.js +0 -0
  88. package/src/components/Table/Table.vue +0 -0
  89. package/src/components/Tabs/Tab.vue +4 -0
  90. package/src/components/Tabs/Tabs.vue +5 -0
  91. package/src/components/Tabs/tabs.scss +8 -2
  92. package/src/components/TagPill/TagPill.vue +6 -0
  93. package/src/components/TagPill/constants.js +0 -0
  94. package/src/components/ToggleTip/ToggleTip.stories.js +0 -0
  95. package/src/components/ToggleTip/ToggleTip.vue +0 -0
  96. package/src/components/Tooltip/Tooltip.stories.js +0 -0
  97. package/src/components/Tooltip/Tooltip.vue +1 -1
  98. package/src/components/TreeSelect/Option.vue +48 -16
  99. package/src/components/TreeSelect/Select.vue +101 -39
  100. package/src/components/TreeSelect/mixins/InfinityLoaderMixin.js +40 -0
  101. package/src/components/TreeSelect/scss/option.scss +31 -0
  102. package/src/components/TreeSelect/scss/select.scss +48 -2
  103. package/src/constants/events.js +0 -0
  104. package/src/constants/keyCodes.js +1 -0
  105. package/src/directives/outside/outside.js +0 -0
  106. package/src/directives/tooltip/TooltipController.js +2 -0
  107. package/src/directives/tooltip/textOverflowTooltip.js +3 -1
  108. package/src/directives/tooltip/tooltip.js +15 -0
  109. package/src/helpers/generateUID.js +0 -0
  110. package/src/helpers/getHrefFromID.js +0 -0
  111. package/src/helpers/multiLineOverflows.js +0 -0
  112. package/src/helpers/stripHtml.js +4 -0
  113. package/src/index.js +2 -0
  114. package/src/stories/link.stories.js +0 -0
  115. package/static/Logo.svg +0 -0
  116. package/vite.config.js +0 -0
@@ -8,12 +8,13 @@
8
8
  v-model="phone"
9
9
  v-bind="$attrs"
10
10
  @country-changed="countryChanged"
11
- :input-options="{ name: inputName, id: inputName }"
11
+ :input-options="{ name: inputName, id: inputName, autocomplete: 'off' }"
12
12
  :auto-default-country="autoDefaultCountry"
13
- :dropdown-options="{ showSearchBox: true, showFlags: true }"
13
+ :dropdown-options="{ showSearchBox: true, showFlags: true, tabindex: 0 }"
14
14
  :defaultCountry="defaultCountry"
15
15
  :ignoredCountries="ignoredCountries"
16
- :class="{ error: error || errorMessage.length }"
16
+ :class="{ error: error || errorMessage.length, disabled }"
17
+ :disabled="disabled"
17
18
  style-classes="ib-phone-input"
18
19
  ref="vueTel"
19
20
  >
@@ -24,14 +25,19 @@
24
25
  </template>
25
26
 
26
27
  <script>
27
- import { VueTelInput } from "vue-tel-input";
28
28
  import IbIcon from "../../Icon.vue";
29
29
  import IbAlert from "../../Alert/Alert.vue";
30
30
  import { OutsideDirective as Outside } from "../../../directives/outside/outside";
31
+ import { VueTelInput } from 'vue-tel-input';
32
+ import 'vue-tel-input/vue-tel-input.css'
31
33
 
32
34
  export default {
33
35
  directives: { Outside },
34
36
  props: {
37
+ modelValue: {
38
+ type: String
39
+ },
40
+ value: String,
35
41
  inputName: {
36
42
  type: String,
37
43
  default: "phone",
@@ -40,10 +46,6 @@ export default {
40
46
  type: Boolean,
41
47
  default: true,
42
48
  },
43
- value: {
44
- type: String,
45
- default: "",
46
- },
47
49
  ignoredCountries: {
48
50
  type: Array,
49
51
  default: () => [],
@@ -56,7 +58,12 @@ export default {
56
58
  type: String,
57
59
  default: "",
58
60
  },
61
+ disabled: {
62
+ type: Boolean,
63
+ default: false,
64
+ }
59
65
  },
66
+ emits: ['update:modelValue', 'onReady'],
60
67
  components: {
61
68
  VueTelInput,
62
69
  IbAlert,
@@ -65,16 +72,24 @@ export default {
65
72
  data() {
66
73
  return {
67
74
  vueTel: null,
68
- phone: "",
69
75
  dialCode: "",
70
76
  defaultCountry: "US",
77
+ allowChange: false
71
78
  };
72
79
  },
73
80
  mounted() {
74
81
  this.vueTel = this.$refs.vueTel;
75
82
 
76
- if (this.value) {
77
- this.phone = this.value[0] === "+" ? this.value : "+" + this.value;
83
+ this.$emit('onReady');
84
+ },
85
+ computed: {
86
+ phone: {
87
+ get() {
88
+ return this.modelValue
89
+ },
90
+ set(value) {
91
+ this.$emit('update:modelValue', value)
92
+ }
78
93
  }
79
94
  },
80
95
  methods: {
@@ -102,4 +117,3 @@ export default {
102
117
  <style lang="scss">
103
118
  @import "./phoneInput.scss";
104
119
  </style>
105
- <style src="vue-tel-input/vue-tel-input.css"></style>
@@ -43,6 +43,39 @@ $dropdown-item-selected-border-color: $blue-900;
43
43
  }
44
44
  }
45
45
 
46
+ &.disabled {
47
+ .vti__input {
48
+ background-color: $gray-100 !important;
49
+ color: $neutral-500 !important;
50
+ border-color: $input-border-color !important;
51
+
52
+ &:focus {
53
+ outline: none !important;
54
+ border-bottom: 1px solid $input-border-color !important;
55
+ border-radius: 4px 4px 0 0 !important;
56
+ }
57
+ }
58
+
59
+ .vti__dropdown {
60
+ background-color: $gray-100 !important;
61
+ border-color: $input-border-color !important;
62
+ cursor: not-allowed;
63
+
64
+ .vti__selection {
65
+ filter:grayscale(1);
66
+ }
67
+
68
+ &:focus {
69
+ .vti__selection {
70
+ outline: none !important;
71
+ background-color: $gray-100 !important;
72
+ border-bottom: 1px solid $input-border-color !important;
73
+ border-radius: 4px 4px 0 0 !important;
74
+ }
75
+ }
76
+ }
77
+ }
78
+
46
79
  .vti__dropdown {
47
80
  padding: 0;
48
81
  border-radius: 4px 4px 0 0;
@@ -100,17 +133,16 @@ $dropdown-item-selected-border-color: $blue-900;
100
133
  .vti__input {
101
134
  background-color: transparent;
102
135
  width: 100%;
103
- margin: 0;
104
- margin-bottom: 6.5px;
105
- border-left: 0px;
106
- border-right: 0px;
107
- border-top: 0px;
136
+ margin: 0 0 6.5px;
137
+ border-left: 0;
138
+ border-right: 0;
139
+ border-top: 0;
108
140
  border-radius: 0;
109
141
 
110
142
  &::placeholder {
111
143
  @include Ib-H4-regular-italic;
112
144
  color: $input-placeholder-color;
113
- }
145
+ }
114
146
 
115
147
  &:focus {
116
148
  border-radius: 0;
@@ -3,19 +3,17 @@
3
3
  role="radio"
4
4
  :class="classes"
5
5
  :for="id"
6
- :aria-checked="checked"
7
- @click.prevent="onClick"
6
+ :aria-checked="isChecked"
8
7
  >
9
8
  <input
10
9
  type="radio"
11
10
  :name="name"
12
11
  :id="id"
13
12
  :value="value"
14
- :checked="checked"
13
+ :checked="isChecked"
15
14
  :disabled="disabled"
16
15
  ref="radio"
17
- @input.stop
18
- @change="onChange"
16
+ @change="checkHandler"
19
17
  />
20
18
  <span class="ib-radio-body" :class="{ 'without-text': !label?.length }">
21
19
  <span class="ib-radio-input"></span>
@@ -29,11 +27,8 @@ import generateUID from "../../../helpers/generateUID";
29
27
 
30
28
  export default {
31
29
  name: "IbRadio",
32
- model: {
33
- prop: "isChecked",
34
- event: "input",
35
- },
36
30
  props: {
31
+ modelValue: '',
37
32
  label: String,
38
33
  error: {
39
34
  type: Boolean,
@@ -49,63 +44,40 @@ export default {
49
44
  },
50
45
  },
51
46
  value: {
52
- type: String,
47
+ type: [String, Number],
53
48
  required: true,
54
49
  },
55
- isChecked: {
56
- type: Boolean,
57
- default: false,
58
- },
59
50
  disabled: {
60
51
  type: Boolean,
61
52
  default: false,
62
53
  },
63
54
  },
64
- watch: {
65
- isChecked(value) {
66
- this.checked = value;
67
- },
68
- },
69
- mounted() {
70
- this.$globalEvents.$on(`radio:update:${this.name}`, (uid) => {
71
- if (this.uid !== uid) {
72
- this.checked = false;
73
- }
74
- });
75
- },
55
+ emits: ['update:modelValue'],
76
56
  data() {
77
57
  return {
78
- checked: this.isChecked,
79
58
  uid: generateUID(),
80
59
  };
81
60
  },
61
+ mounted() {
62
+ this.checked = this.isChecked;
63
+ },
82
64
  methods: {
83
- onClick() {
84
- if (!this.disabled) {
85
- this.checked = !this.checked;
86
- this.$globalEvents.$emit(`radio:update:${this.name}`, this.uid);
87
- this.$emit("input", this.checked);
88
- this.$emit("change", this.checked);
89
- }
90
- },
91
- onChange() {
92
- if (!this.disabled) {
93
- this.checked = !this.checked;
94
- this.$globalEvents.$emit(`radio:update:${this.name}`, this.uid);
95
- this.$emit("change", this.checked);
96
- this.$emit("input", this.checked);
97
- }
98
- },
65
+ checkHandler() {
66
+ this.$emit('update:modelValue', this.value)
67
+ }
99
68
  },
100
69
  computed: {
101
70
  classes() {
102
71
  return {
103
72
  "ib-radio": true,
104
73
  "has-error": this.error,
105
- "radio-filled": this.checked,
74
+ "radio-filled": this.isChecked,
106
75
  "radio-disabled": this.disabled,
107
76
  };
108
77
  },
78
+ isChecked() {
79
+ return this.modelValue === this.value
80
+ }
109
81
  },
110
82
  };
111
83
  </script>
@@ -30,12 +30,15 @@ $radio-border-filled-disabled: $neutral-500;
30
30
  .ib-radio {
31
31
  display: inline-flex;
32
32
  cursor: pointer;
33
+ position: relative;
33
34
 
34
35
  input {
35
36
  opacity: 0;
36
37
  position: absolute;
37
- top: -100%;
38
- right: -100%;
38
+ width: 1px;
39
+ height: 1px;
40
+ z-index: -1;
41
+
39
42
 
40
43
  &:focus + .ib-radio-body {
41
44
  border-radius: 4px;
@@ -7,6 +7,7 @@
7
7
  disable: disable,
8
8
  }"
9
9
  >
10
+
10
11
  <ib-character-count
11
12
  v-if="characterLimit"
12
13
  :character-limit="characterLimit"
@@ -23,18 +24,19 @@
23
24
  {{ characterLimitErrorMessage }}
24
25
  </ib-alert>
25
26
 
27
+ <input :name="name" type="hidden" :disabled="disable" :value="data">
28
+
26
29
  <div class="ib-text-editor-wrapper" :class="{ disable: disable }">
27
30
  <div
28
31
  class="ib-text-editor"
29
- :style="{ height: height ? height + 'px' : '' }"
30
32
  ref="wrapper"
31
33
  >
32
34
  <QuillEditor
35
+ aria-label="text-editor"
33
36
  @textChange="onChange"
34
37
  @blur="onBlur"
35
38
  @focus="onFocus"
36
39
  ref="quill"
37
- toolbar="#toolbar"
38
40
  v-model:content="data"
39
41
  contentType="html"
40
42
  :options="config"
@@ -42,8 +44,17 @@
42
44
  ></QuillEditor>
43
45
  </div>
44
46
  <div id="toolbar" class="toolbar" ref="toolbar">
47
+ <div class="toolbar-group header-toolbar-group" v-show="placeholders.length">
48
+ <label class="toolbar-group__label" for="placeholders">Placeholder Selector</label>
49
+ <select id="placeholders" class="ql-placeholder">
50
+ <option selected value="default" class="disabled"></option>
51
+ <option v-for="placeholder in placeholders" :key="placeholder.id" :value="placeholder.id">{{ placeholder.label }}</option>
52
+ </select>
53
+ </div>
54
+
45
55
  <div class="toolbar-group header-toolbar-group">
46
- <select class="ql-header">
56
+ <label class="toolbar-group__label" for="header-selector">Header Selector</label>
57
+ <select id="header-selector" class="ql-header">
47
58
  <option value="1"></option>
48
59
  <option value="2"></option>
49
60
  <option value="3"></option>
@@ -56,34 +67,42 @@
56
67
 
57
68
  <div class="toolbar-group">
58
69
  <ib-icon-button
70
+ aria-label="button-bold"
59
71
  class="toolbar-item ql-bold"
60
72
  kind="ghost"
61
73
  ></ib-icon-button>
62
74
  <ib-icon-button
75
+ aria-label="button-italic"
63
76
  class="toolbar-item ql-italic"
64
77
  kind="ghost"
65
78
  ></ib-icon-button>
66
79
  <ib-icon-button
80
+ aria-label="button-underline"
67
81
  class="toolbar-item ql-underline"
68
82
  kind="ghost"
69
83
  ></ib-icon-button>
70
84
  <ib-icon-button
85
+ aria-label="button-strike"
71
86
  class="toolbar-item ql-strike"
72
87
  kind="ghost"
73
88
  ></ib-icon-button>
74
89
  </div>
75
90
 
76
91
  <div class="toolbar-group">
77
- <select class="ql-background"></select>
78
- <select class="ql-color"></select>
92
+ <label class="toolbar-group__label" for="background-selector">Background Selector</label>
93
+ <select id="background-selector" class="ql-background"></select>
94
+ <label class="toolbar-group__label" for="color-selector">Background Color Selector</label>
95
+ <select id="color-selector" class="ql-color"></select>
79
96
  </div>
80
97
 
81
98
  <div class="toolbar-group">
82
99
  <ib-icon-button
100
+ aria-label="button-code-block"
83
101
  class="toolbar-item ql-code-block"
84
102
  kind="ghost"
85
103
  ></ib-icon-button>
86
104
  <ib-icon-button
105
+ aria-label="button-link"
87
106
  class="toolbar-item ql-link"
88
107
  kind="ghost"
89
108
  ></ib-icon-button>
@@ -91,20 +110,24 @@
91
110
 
92
111
  <div class="toolbar-group">
93
112
  <ib-icon-button
113
+ aria-label="button-align"
94
114
  class="toolbar-item ql-align"
95
115
  kind="ghost"
96
116
  ></ib-icon-button>
97
117
  <ib-icon-button
118
+ aria-label="button-align-center"
98
119
  class="ql-align toolbar-item"
99
120
  value="center"
100
121
  kind="ghost"
101
122
  ></ib-icon-button>
102
123
  <ib-icon-button
124
+ aria-label="button-align-right"
103
125
  class="ql-align toolbar-item"
104
126
  value="right"
105
127
  kind="ghost"
106
128
  ></ib-icon-button>
107
129
  <ib-icon-button
130
+ aria-label="button-align-justify"
108
131
  class="ql-align toolbar-item"
109
132
  value="justify"
110
133
  kind="ghost"
@@ -113,17 +136,20 @@
113
136
 
114
137
  <div class="toolbar-group">
115
138
  <ib-icon-button
139
+ aria-label="button-ordered-list"
116
140
  class="ql-list toolbar-item"
117
141
  value="ordered"
118
142
  kind="ghost"
119
143
  ></ib-icon-button>
120
144
  <ib-icon-button
145
+ aria-label="button-bullet-list"
121
146
  class="ql-list toolbar-item"
122
147
  value="bullet"
123
148
  kind="ghost"
124
149
  ></ib-icon-button>
125
150
 
126
151
  <ib-icon-button
152
+ aria-label="button-alphabet-list"
127
153
  class="ql-alphabet-list alphabet-list toolbar-item"
128
154
  kind="ghost"
129
155
  ></ib-icon-button>
@@ -134,29 +160,43 @@
134
160
  </template>
135
161
 
136
162
  <script>
137
- import { QuillEditor, Quill } from "@vueup/vue-quill";
163
+ import {Quill, QuillEditor} from "@vueup/vue-quill";
138
164
  import IbIconButton from "../../IconButton/IconButton.vue";
139
165
  import IbAlert from "../../Alert/Alert.vue";
140
166
  import IbCharacterCount from "../CharactersCount.vue";
141
- import { AlphabetList, AlphabetListItem } from "./plugins/alphabetList";
167
+ import {AlphabetList, AlphabetListItem} from "./plugins/alphabetList";
168
+ import { stripHtml } from "../../../helpers/stripHtml";
169
+ import getPlaceholderModule from 'quill-placeholder-module';
142
170
  import "@vueup/vue-quill/dist/vue-quill.snow.css";
143
171
 
144
172
  import {
173
+ ALIGN_CENTER,
174
+ ALIGN_JUSTIFY,
175
+ ALIGN_LEFT,
176
+ ALIGN_RIGHT,
145
177
  BOLD,
146
- ITALIC,
147
- UNDERLINE,
148
- STRIKE,
149
178
  CODE,
179
+ ITALIC,
150
180
  LINK,
151
- ALIGN_LEFT,
152
- ALIGN_CENTER,
153
- ALIGN_RIGHT,
154
- ALIGN_JUSTIFY,
155
- LIST_ORDERED,
156
- LIST_BULLET,
157
181
  LIST_ALPHABET,
182
+ LIST_BULLET,
183
+ LIST_ORDERED,
184
+ STRIKE,
185
+ UNDERLINE,
158
186
  } from "./icons/toolbarIcons";
159
187
 
188
+ Quill.register(Quill.import('attributors/attribute/direction'), true);
189
+ Quill.register(Quill.import('attributors/class/align'), true);
190
+ Quill.register(Quill.import('attributors/class/direction'), true);
191
+ Quill.register(Quill.import('attributors/class/font'), true);
192
+ Quill.register(Quill.import('attributors/class/size'), true);
193
+ Quill.register(Quill.import('attributors/style/align'), true);
194
+ Quill.register(Quill.import('attributors/style/background'), true);
195
+ Quill.register(Quill.import('attributors/style/color'), true);
196
+ Quill.register(Quill.import('attributors/style/direction'), true);
197
+ Quill.register(Quill.import('attributors/style/font'), true);
198
+ Quill.register(Quill.import('attributors/style/size'), true);
199
+
160
200
  const icons = Quill.import("ui/icons");
161
201
  icons.bold = BOLD;
162
202
  icons.italic = ITALIC;
@@ -177,16 +217,29 @@ Quill.register({
177
217
  "formats/alphabet-list/item": AlphabetListItem,
178
218
  });
179
219
 
220
+ Quill.register('modules/placeholder', getPlaceholderModule(Quill, {
221
+ className: 'ql-placeholder-content'
222
+ }))
223
+
224
+
180
225
  Quill.register(icons);
181
226
  Quill.debug("error");
182
227
 
183
228
  export default {
184
229
  name: "IbTextEditor",
185
230
  props: {
231
+ name: {
232
+ type: String,
233
+ required: true
234
+ },
186
235
  placeholder: {
187
236
  type: String,
188
237
  default: "",
189
238
  },
239
+ placeholders: {
240
+ type: Array,
241
+ default: () => []
242
+ },
190
243
  modelValue: {
191
244
  type: String,
192
245
  },
@@ -230,10 +283,8 @@ export default {
230
283
  type: String,
231
284
  default: "",
232
285
  },
233
- height: {
234
- type: String,
235
- },
236
286
  },
287
+ emits: ['onOverLimitHandler', 'update:modelValue', 'change', 'blur'],
237
288
  mounted() {
238
289
  // Reset default styles for toolbar
239
290
  this.$refs.toolbar.classList.remove("ql-toolbar");
@@ -256,24 +307,61 @@ export default {
256
307
  this.data = val;
257
308
  },
258
309
  data(val) {
259
- this.$emit("update:modelValue", val);
310
+ const cleanedData = this.cleanPlaceholderSpans(val);
311
+ this.$emit("update:modelValue", cleanedData);
260
312
  },
313
+ characterOverLimit(value) {
314
+ this.$emit('onOverLimitHandler', value);
315
+ }
261
316
  },
262
317
  methods: {
263
318
  onChange() {
319
+ let data = this.cleanPlaceholderSpans(this.data);
320
+ this.data = this.patchListStylePosition(data);
321
+
264
322
  this.updateCharacterLength();
265
323
  this.$emit("change", this.data);
266
324
  },
267
325
  onBlur(instance) {
268
- this.$emit("blur", this.data, instance);
326
+ this.$emit("blur", this.cleanPlaceholderSpans(this.data), instance);
269
327
  this.isFocus = false;
270
328
  },
271
329
  onFocus() {
272
330
  this.isFocus = true;
273
331
  },
274
332
  updateCharacterLength() {
275
- this.characterLength = this.$refs.quill.getText().length - 1;
333
+ this.characterLength = stripHtml(this.data).length;
276
334
  },
335
+ cleanPlaceholderSpans(html) {
336
+ if (!html) return html;
337
+
338
+ let prevHtml;
339
+ do {
340
+ prevHtml = html;
341
+ html = html.replace(/<span contenteditable="false">([\s\S]*?)<\/span>/g, (_, content) => {
342
+ return content.replace(/[\u200B-\u200F\uFEFF]/g, '');
343
+ });
344
+ } while (prevHtml !== html);
345
+
346
+ return html;
347
+ },
348
+ patchListStylePosition(html) {
349
+ const tmp = document.createElement('div');
350
+ tmp.innerHTML = html;
351
+
352
+ tmp.querySelectorAll('ul[style*="text-align"], ol[style*="text-align"], li[style*="text-align"]').forEach(el => {
353
+ const style = el.getAttribute('style') ?? '';
354
+
355
+ if (!/list-style-position\s*:\s*inside/i.test(style)) {
356
+ const newStyle =
357
+ (style.trim().endsWith(';') || style.trim() === '' ? style : style + ';') +
358
+ ' list-style-position: inside;';
359
+ el.setAttribute('style', newStyle);
360
+ }
361
+ });
362
+
363
+ return tmp.innerHTML;
364
+ }
277
365
  },
278
366
  computed: {
279
367
  config() {
@@ -281,6 +369,13 @@ export default {
281
369
  placeholder: this.data.length ? "" : this.placeholder,
282
370
  readOnly: this.readOnly ? this.readOnly : this.disable,
283
371
  enable: this.enable,
372
+ modules: {
373
+ toolbar: {container: '#toolbar'},
374
+ placeholder: {
375
+ delimiters: ['{{', '}}'],
376
+ placeholders: this.placeholders
377
+ }
378
+ },
284
379
  };
285
380
 
286
381
  return Object.assign(config, this.options);