@witchcraft/ui 0.1.1 → 0.1.3

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 (122) hide show
  1. package/dist/module.cjs +5 -0
  2. package/dist/module.d.ts +36 -0
  3. package/dist/module.json +2 -2
  4. package/dist/module.mjs +2 -1
  5. package/dist/runtime/assets/utils.css +1 -1
  6. package/dist/runtime/components/Aria/Aria.vue +9 -5
  7. package/dist/runtime/components/Focus.stories.d.ts +11 -0
  8. package/dist/runtime/components/Focus.stories.js +53 -0
  9. package/dist/runtime/components/Icon/Icon.vue +30 -10
  10. package/dist/runtime/components/LibButton/LibButton.stories.d.ts +12 -0
  11. package/dist/runtime/components/LibButton/LibButton.stories.js +94 -0
  12. package/dist/runtime/components/LibButton/LibButton.vue +72 -58
  13. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.d.ts +14 -0
  14. package/dist/runtime/components/LibCheckbox/LibCheckbox.stories.js +29 -0
  15. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue +74 -48
  16. package/dist/runtime/components/LibColorInput/LibColorInput.stories.d.ts +7 -0
  17. package/dist/runtime/components/LibColorInput/LibColorInput.stories.js +58 -0
  18. package/dist/runtime/components/LibColorInput/LibColorInput.vue +107 -63
  19. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.d.ts +9 -0
  20. package/dist/runtime/components/LibColorPicker/LibColorPicker.stories.js +68 -0
  21. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue +352 -271
  22. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.d.ts +7 -0
  23. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.stories.js +36 -0
  24. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue +56 -32
  25. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.d.ts +11 -0
  26. package/dist/runtime/components/LibDatePicker/LibDatePicker.stories.js +98 -0
  27. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue +38 -17
  28. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue +82 -53
  29. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue +67 -50
  30. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue +8 -7
  31. package/dist/runtime/components/LibDebug/LibDebug.stories.d.ts +9 -0
  32. package/dist/runtime/components/LibDebug/LibDebug.stories.js +46 -0
  33. package/dist/runtime/components/LibDebug/LibDebug.vue +70 -42
  34. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue +31 -18
  35. package/dist/runtime/components/LibFileInput/LibFileInput.stories.d.ts +10 -0
  36. package/dist/runtime/components/LibFileInput/LibFileInput.stories.js +63 -0
  37. package/dist/runtime/components/LibFileInput/LibFileInput.vue +156 -113
  38. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.d.ts +33 -0
  39. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.stories.js +384 -0
  40. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue +241 -215
  41. package/dist/runtime/components/LibLabel/LibLabel.stories.d.ts +6 -0
  42. package/dist/runtime/components/LibLabel/LibLabel.stories.js +25 -0
  43. package/dist/runtime/components/LibLabel/LibLabel.vue +46 -30
  44. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.d.ts +23 -0
  45. package/dist/runtime/components/LibMultiValues/LibMultiValues.stories.js +61 -0
  46. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue +58 -44
  47. package/dist/runtime/components/LibNotifications/LibNotification.stories.d.ts +15 -0
  48. package/dist/runtime/components/LibNotifications/LibNotification.stories.js +126 -0
  49. package/dist/runtime/components/LibNotifications/LibNotification.vue +48 -32
  50. package/dist/runtime/components/LibNotifications/LibNotifications.stories.d.ts +6 -0
  51. package/dist/runtime/components/LibNotifications/LibNotifications.stories.js +109 -0
  52. package/dist/runtime/components/LibNotifications/LibNotifications.vue +83 -63
  53. package/dist/runtime/components/LibPagination/LibPagination.stories.d.ts +6 -0
  54. package/dist/runtime/components/LibPagination/LibPagination.stories.js +40 -0
  55. package/dist/runtime/components/LibPagination/LibPagination.vue +111 -67
  56. package/dist/runtime/components/LibPalette/LibPalette.stories.d.ts +6 -0
  57. package/dist/runtime/components/LibPalette/LibPalette.stories.js +20 -0
  58. package/dist/runtime/components/LibPalette/LibPalette.vue +23 -20
  59. package/dist/runtime/components/LibPopup/LibPopup.stories.d.ts +14 -0
  60. package/dist/runtime/components/LibPopup/LibPopup.stories.js +147 -0
  61. package/dist/runtime/components/LibPopup/LibPopup.vue +351 -314
  62. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.d.ts +10 -0
  63. package/dist/runtime/components/LibProgressBar/LibProgressBar.stories.js +81 -0
  64. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue +91 -70
  65. package/dist/runtime/components/LibRecorder/LibRecorder.stories.d.ts +19 -0
  66. package/dist/runtime/components/LibRecorder/LibRecorder.stories.js +63 -0
  67. package/dist/runtime/components/LibRecorder/LibRecorder.vue +177 -133
  68. package/dist/runtime/components/LibRoot/LibRoot.vue +100 -73
  69. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.d.ts +26 -0
  70. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.stories.js +78 -0
  71. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue +77 -49
  72. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.d.ts +27 -0
  73. package/dist/runtime/components/LibSuggestions/LibSuggestions.stories.js +112 -0
  74. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue +156 -123
  75. package/dist/runtime/components/LibTable/LibTable.stories.d.ts +16 -0
  76. package/dist/runtime/components/LibTable/LibTable.stories.js +156 -0
  77. package/dist/runtime/components/LibTable/LibTable.vue +99 -63
  78. package/dist/runtime/components/Reset.stories.d.ts +5 -0
  79. package/dist/runtime/components/Reset.stories.js +19 -0
  80. package/dist/runtime/components/Scrolling.stories.d.ts +6 -0
  81. package/dist/runtime/components/Scrolling.stories.js +44 -0
  82. package/dist/runtime/components/Template/NAME.vue +36 -15
  83. package/dist/runtime/components/TestControls/TestControls.vue +9 -6
  84. package/dist/runtime/composables/useScrollNearContainerEdges.stories.d.ts +7 -0
  85. package/dist/runtime/composables/useScrollNearContainerEdges.stories.js +85 -0
  86. package/dist/types.d.mts +6 -2
  87. package/dist/types.d.ts +7 -0
  88. package/package.json +11 -5
  89. package/src/module.ts +2 -1
  90. package/src/runtime/assets/utils.css +5 -5
  91. package/src/runtime/components/LibButton/LibButton.vue +2 -6
  92. package/src/runtime/nuxt/plugins/vue-plugin.ts +1 -1
  93. package/dist/runtime/components/Aria/Aria.vue.d.ts +0 -5
  94. package/dist/runtime/components/Icon/Icon.vue.d.ts +0 -21
  95. package/dist/runtime/components/LibButton/LibButton.vue.d.ts +0 -36
  96. package/dist/runtime/components/LibCheckbox/LibCheckbox.vue.d.ts +0 -42
  97. package/dist/runtime/components/LibColorInput/LibColorInput.vue.d.ts +0 -63
  98. package/dist/runtime/components/LibColorPicker/LibColorPicker.vue.d.ts +0 -61
  99. package/dist/runtime/components/LibDarkModeSwitcher/LibDarkModeSwitcher.vue.d.ts +0 -22
  100. package/dist/runtime/components/LibDatePicker/LibDatePicker.vue.d.ts +0 -40
  101. package/dist/runtime/components/LibDatePicker/LibRangeDatePicker.vue.d.ts +0 -34
  102. package/dist/runtime/components/LibDatePicker/LibSingleDatePicker.vue.d.ts +0 -34
  103. package/dist/runtime/components/LibDatePicker/LibTimeZonePicker.vue.d.ts +0 -22
  104. package/dist/runtime/components/LibDebug/LibDebug.vue.d.ts +0 -32
  105. package/dist/runtime/components/LibDevOnly/LibDevOnly.vue.d.ts +0 -22
  106. package/dist/runtime/components/LibFileInput/LibFileInput.vue.d.ts +0 -43
  107. package/dist/runtime/components/LibInputDeprecated/LibInputDeprecated.vue.d.ts +0 -165
  108. package/dist/runtime/components/LibLabel/LibLabel.vue.d.ts +0 -27
  109. package/dist/runtime/components/LibMultiValues/LibMultiValues.vue.d.ts +0 -29
  110. package/dist/runtime/components/LibNotifications/LibNotification.vue.d.ts +0 -17
  111. package/dist/runtime/components/LibNotifications/LibNotifications.vue.d.ts +0 -13
  112. package/dist/runtime/components/LibPagination/LibPagination.vue.d.ts +0 -104
  113. package/dist/runtime/components/LibPalette/LibPalette.vue.d.ts +0 -14
  114. package/dist/runtime/components/LibPopup/LibPopup.vue.d.ts +0 -46
  115. package/dist/runtime/components/LibProgressBar/LibProgressBar.vue.d.ts +0 -41
  116. package/dist/runtime/components/LibRecorder/LibRecorder.vue.d.ts +0 -77
  117. package/dist/runtime/components/LibRoot/LibRoot.vue.d.ts +0 -41
  118. package/dist/runtime/components/LibSimpleInput/LibSimpleInput.vue.d.ts +0 -35
  119. package/dist/runtime/components/LibSuggestions/LibSuggestions.vue.d.ts +0 -94
  120. package/dist/runtime/components/LibTable/LibTable.vue.d.ts +0 -45
  121. package/dist/runtime/components/Template/NAME.vue.d.ts +0 -17
  122. package/dist/runtime/components/TestControls/TestControls.vue.d.ts +0 -5
@@ -4,9 +4,8 @@
4
4
  contenteditable=false is because of storybook, it's shortcuts interfere when not using real input elements
5
5
  -->
6
6
  <div
7
- :id="id ?? fallbackId"
8
- :class="twMerge(
9
- `recorder
7
+ :id="id?? fallbackId"
8
+ :class="twMerge(`recorder
10
9
  flex items-center
11
10
  gap-2
12
11
  px-2
@@ -14,38 +13,37 @@
14
13
  focus-outline-no-offset
15
14
  rounded-sm
16
15
  `,
17
- border && `
16
+ border &&`
18
17
  border
19
18
  border-neutral-500
20
19
  focus:border-accent-500
21
20
  `,
22
- (disabled || readonly) && `
21
+
22
+ (disabled || readonly) && `
23
23
  text-neutral-400
24
24
  dark:text-neutral-600
25
25
  `,
26
- (disabled || readonly) && border && `
26
+ (disabled || readonly) && border && `
27
27
  bg-neutral-50
28
28
  dark:bg-neutral-950
29
29
  border-neutral-400
30
30
  dark:border-neutral-600
31
- `,
32
- $attrs.class
33
- )"
31
+ `
32
+ , ($attrs as any).class)"
34
33
  :aria-disabled="disabled"
35
34
  :aria-readonly="readonly"
36
35
  :tabindex="disabled ? -1 : 0"
37
36
  :title="recording ? recordingTitle : tempValue"
38
37
  contenteditable="false"
39
38
  ref="recorderEl"
40
- v-bind="{ ...ariaLabel, ...$attrs, class: void 0 }"
39
+ v-bind="{...ariaLabel, ...$attrs, class:undefined}"
41
40
  @blur="handleBlurRecorder($event)"
42
41
  @click="handleClickRecorder($event)"
43
42
  @keydown.space.prevent="handleClickRecorder($event, true)"
44
43
  >
45
44
  <!-- :aria-description="recording ? recordingTitle : ''" -->
46
45
  <div
47
- :class="twMerge(
48
- `recorder--indicator
46
+ :class="twMerge(`recorder--indicator
49
47
  inline-block
50
48
  bg-red-700
51
49
  rounded-full
@@ -54,145 +52,191 @@
54
52
  shrink-0
55
53
  hover:bg-red-500
56
54
  `,
57
- recording && `
55
+ recording && `
58
56
  animate-[blink_1s_infinite]
59
57
  bg-red-500
60
58
  `,
61
- (disabled || readonly) && `
59
+ (disabled || readonly) && `
62
60
  bg-neutral-500
63
61
  `
64
- )"
62
+ )"
65
63
  ref="recorderIndicatorEl"
66
64
  />
67
65
  <div class="recorder--value before:content-vertical-holder truncate">
68
- {{ recording ? recordingValue ?? t("recorder.recording") : tempValue }}
66
+ {{ recording
67
+ ? recordingValue ?? t("recorder.recording")
68
+ : tempValue }}
69
69
  </div>
70
70
  </div>
71
71
  </template>
72
+ <script setup lang="ts">
73
+ import { keys } from "@alanscodelog/utils/keys.js"
74
+ import { computed, type HTMLAttributes ,onBeforeUnmount, onMounted, type PropType, ref, watch, watchPostEffect } from "vue"
75
+
76
+ import { useAriaLabel } from "../../composables/useAriaLabel.js"
77
+ import { useInjectedI18n } from "../../composables/useInjectedI18n.js"
78
+ import { twMerge } from "../../utils/twMerge.js"
79
+ import { type BaseInteractiveProps, baseInteractivePropsDefaults, getFallbackId, type LabelProps, type LinkableByIdProps,type TailwindClassProp } from "../shared/props.js"
72
80
 
73
- <script setup>
74
- import { keys } from "@alanscodelog/utils/keys.js";
75
- import { computed, onBeforeUnmount, onMounted, ref, watch, watchPostEffect } from "vue";
76
- import { useAriaLabel } from "../../composables/useAriaLabel.js";
77
- import { useInjectedI18n } from "../../composables/useInjectedI18n.js";
78
- import { twMerge } from "../../utils/twMerge.js";
79
- import { baseInteractivePropsDefaults, getFallbackId } from "../shared/props.js";
80
81
  defineOptions({
81
- name: "lib-recorder",
82
- inheritAttrs: false
83
- });
84
- const t = useInjectedI18n();
85
- const emits = defineEmits(["recorder:blur", "recorder:click", "focus:parent"]);
86
- const fallbackId = getFallbackId();
87
- const props = defineProps(/* @__PURE__ */ _mergeDefaults({
88
- id: { type: String, required: false },
89
- disabled: { type: Boolean, required: false },
90
- readonly: { type: Boolean, required: false },
91
- border: { type: Boolean, required: false },
92
- unstyle: { type: Boolean, required: false },
93
- label: { type: String, required: false },
94
- recordingValue: { type: String, required: false },
95
- recordingTitle: { type: String, required: false },
96
- recorder: { type: null, required: false },
97
- binders: { type: null, required: false }
98
- }, {
99
- recordingTitle: "",
100
- id: void 0,
101
- binders: void 0,
102
- recorder: void 0,
103
- ...baseInteractivePropsDefaults
104
- }));
105
- const recording = defineModel("recording", { type: Boolean, ...{ required: false, default: false } });
106
- const modelValue = defineModel({ type: String, ...{ required: true } });
107
- const recorderEl = ref(null);
108
- const recorderIndicatorEl = ref(null);
109
- const canEdit = computed(() => !props.disabled && !props.readonly);
110
- const tempValue = ref(modelValue.value);
82
+ name: "lib-recorder",
83
+ inheritAttrs: false,
84
+ })
85
+ const t = useInjectedI18n()
86
+
87
+ const emits = defineEmits<{
88
+ /** Recorder is blurred */
89
+ (e: "recorder:blur", $event: FocusEvent): void
90
+ /** Recorder is clicked. The component's indicator and recorder elements are passed to help filter out those clicks. */
91
+ (e: "recorder:click", { event, indicator, input }: { event: MouseEvent | KeyboardEvent, indicator: HTMLElement, input: HTMLInputElement }): void
92
+ /* User presses enter. Not emitted when multiple values are used. */
93
+ (e: "focus:parent"): void
94
+ }>()
95
+ const fallbackId = getFallbackId()
96
+ const props = withDefaults(defineProps<Props>(), {
97
+ recordingTitle: "",
98
+ id: undefined,
99
+ binders: undefined,
100
+ recorder: undefined,
101
+ ...baseInteractivePropsDefaults
102
+ })
103
+ /**
104
+ * Puts the element into recording mode if true. See {@link props.recorder}.
105
+ */
106
+ const recording = defineModel<boolean>("recording", { required: false, default: false })
107
+
108
+ /** The final value of the recorder. For intermediate values while recording, pass a recorder and set an appropriate recording value. */
109
+ const modelValue = defineModel<string>({ required: true })
110
+
111
+
112
+ const recorderEl = ref<HTMLInputElement | null>(null)
113
+ const recorderIndicatorEl = ref<HTMLElement | null>(null)
114
+ const canEdit = computed(() => !props.disabled && !props.readonly)
115
+ const tempValue = ref(modelValue.value)
116
+
111
117
  watch([() => props.binders, () => props.binders], () => {
112
- if (recording.value) {
113
- throw new Error("Component was not designed to allow swapping out of binders/recorders while recording");
114
- }
115
- });
118
+ if (recording.value) {
119
+ throw new Error("Component was not designed to allow swapping out of binders/recorders while recording")
120
+ }
121
+ })
122
+
116
123
  watch(modelValue, () => {
117
- tempValue.value = modelValue.value;
118
- });
119
- const ariaLabel = useAriaLabel(props);
120
- const boundListeners = {};
121
- let isBound = false;
122
- const unbindListeners = () => {
123
- if (!isBound) return;
124
- isBound = false;
125
- if (props.recorder) {
126
- for (const key of keys(boundListeners)) {
127
- recorderEl.value?.removeEventListener(key, boundListeners[key]);
128
- delete boundListeners[key];
129
- }
130
- }
131
- if (props.binders && recorderEl.value) {
132
- props.binders.unbind(recorderEl.value);
133
- }
134
- };
135
- const bindListeners = () => {
136
- if (!props.recorder && !props.binders) {
137
- throw new Error("Record is true but no recorder or binders props was passed");
138
- }
139
- if (props.recorder && props.binders) {
140
- throw new Error("Recording is true and was passed both a recorder and a binders prop. Both cannot be used at the same time.");
141
- }
142
- isBound = true;
143
- if (props.recorder) {
144
- for (const key of keys(props.recorder)) {
145
- recorderEl.value?.addEventListener(key, props.recorder[key], { passive: false });
146
- boundListeners[key] = props.recorder[key];
147
- }
148
- }
149
- if (props.binders && recorderEl.value) {
150
- props.binders.bind(recorderEl.value);
151
- }
152
- };
124
+ tempValue.value = modelValue.value
125
+ })
126
+ const ariaLabel = useAriaLabel(props)
127
+
128
+ const boundListeners: Record<string, any> = {}
129
+ let isBound = false
130
+
131
+ const unbindListeners = (): void => {
132
+ if (!isBound) return
133
+ isBound = false
134
+ if (props.recorder) {
135
+ for (const key of keys(boundListeners)) {
136
+ recorderEl.value?.removeEventListener(key, boundListeners[key])
137
+ delete boundListeners[key]
138
+ }
139
+ }
140
+ if (props.binders && recorderEl.value) {
141
+ props.binders.unbind(recorderEl.value as HTMLInputElement)
142
+ }
143
+ }
144
+ const bindListeners = (): void => {
145
+ if (!props.recorder && !props.binders) {
146
+ throw new Error("Record is true but no recorder or binders props was passed")
147
+ }
148
+ if (props.recorder && props.binders) {
149
+ throw new Error("Recording is true and was passed both a recorder and a binders prop. Both cannot be used at the same time.")
150
+ }
151
+ isBound = true
152
+ if (props.recorder) {
153
+ for (const key of keys(props.recorder)) {
154
+ recorderEl.value?.addEventListener(key, props.recorder[key], { passive: false })
155
+ boundListeners[key] = props.recorder[key]
156
+ }
157
+ }
158
+ if (props.binders && recorderEl.value) {
159
+ props.binders.bind(recorderEl.value as HTMLInputElement)
160
+ }
161
+ }
162
+
153
163
  watchPostEffect(() => {
154
- if (!canEdit.value) {
155
- unbindListeners();
156
- recording.value = false;
157
- return;
158
- }
159
- if (recording.value) {
160
- bindListeners();
161
- } else {
162
- if ((props.recorder || props.binders) && isBound) {
163
- unbindListeners();
164
- emits("focus:parent");
165
- }
166
- }
167
- });
164
+ if (!canEdit.value) {
165
+ unbindListeners()
166
+ recording.value = false
167
+ return
168
+ }
169
+ if (recording.value) {
170
+ bindListeners()
171
+ } else {
172
+ if ((props.recorder || props.binders) && isBound) {
173
+ unbindListeners()
174
+ // if we just blur the input then we can't shift+tab backwards
175
+ // this way we can go forwards or backwards without actually focusing since parentEl is not focusable
176
+ // parentEl.value?.focus()
177
+ emits("focus:parent")
178
+ }
179
+ }
180
+ })
181
+
168
182
  onBeforeUnmount(() => {
169
- unbindListeners();
170
- });
183
+ unbindListeners()
184
+ })
171
185
  onMounted(() => {
172
- if (recording.value) {
173
- bindListeners();
174
- }
175
- });
176
- const handleBlurRecorder = (e) => {
177
- if (!canEdit.value) return;
178
- if (props.recorder || props.binders) {
179
- emits("recorder:blur", e);
180
- }
181
- };
182
- const handleClickRecorder = (e, isSpaceKey = false) => {
183
- if (!canEdit.value) return;
184
- if (!recording.value) {
185
- recorderEl.value?.focus();
186
- }
187
- if (props.recorder || props.binders) {
188
- if (isSpaceKey) {
189
- return;
190
- }
191
- emits("recorder:click", { event: e, indicator: recorderIndicatorEl.value, input: recorderEl.value });
192
- }
193
- };
194
- </script>
186
+ if (recording.value) {
187
+ bindListeners()
188
+ }
189
+ })
190
+
191
+ const handleBlurRecorder = (e: FocusEvent): void => {
192
+ if (!canEdit.value) return
193
+ if (props.recorder || props.binders) {
194
+ emits("recorder:blur", e)
195
+ }
196
+ }
195
197
 
196
- <script>
198
+ const handleClickRecorder = (e: MouseEvent | KeyboardEvent, isSpaceKey: boolean = false): void => {
199
+ if (!canEdit.value) return
200
+ if (!recording.value) {
201
+ recorderEl.value?.focus()
202
+ }
203
+ // toggle if clicking on the recording indicator, otherwise only allow starting recording, so if needed, clicks can be recorded
204
+ if (props.recorder || props.binders) {
205
+ if (isSpaceKey) { return }
206
+ emits("recorder:click", { event: e as MouseEvent, indicator: recorderIndicatorEl.value! as HTMLElement, input: recorderEl.value! as HTMLInputElement })
207
+ }
208
+ }
209
+
210
+ </script>
211
+ <script lang="ts">
212
+ type RealProps =
213
+ & LinkableByIdProps
214
+ & BaseInteractiveProps
215
+ & LabelProps
216
+ & {
217
+ border?: boolean
218
+ /** A value to display while recording, if none given the i18n `recorder.recording` key is used. */
219
+ recordingValue?: string
220
+ /** A title to display on the input div while recording. Is also used as the aria-description. */
221
+ recordingTitle?: string
222
+ /**
223
+ * The recorder object is a series of event listeners to attach to the input div while recording is started. If you need to bind directly to the element, see the `binders` prop.
224
+ *
225
+ * The listeners are then unbound when recording is set to false again.
226
+ *
227
+ * Note that the component does not handle the setting of `recording` (unless the component is disabled), `modelValue`, or `recordingValue` at all and has no mechanism for cancelling a recording. It is left to the recorder listeners and any `recorder:*` handlers to determine what to do.
228
+ */
229
+ recorder?: undefined | Record<string, any>
230
+ /** This provides a way to manually attach/remove event listeners to/from the element. It is an alternative to the `recorder` prop, see it for more details. Both cannot be specified at the same time.*/
231
+ binders?: undefined | { bind: (el: HTMLElement) => void, unbind: (el: HTMLElement) => void }
232
+ /** The id of the element. If not provided, the id will be generated automatically. */
233
+ id?: string
234
+ }
197
235
 
236
+ interface Props
237
+ extends
238
+ /** @vue-ignore */
239
+ Partial<Omit<HTMLAttributes,"class"> & TailwindClassProp>,
240
+ RealProps
241
+ { }
198
242
  </script>
@@ -2,36 +2,34 @@
2
2
  <div :id="id"
3
3
  tabindex="-1"
4
4
  :class="twMerge(
5
- showOutline ? 'group outlined outlined-visible' : '[&_*]:outline-hidden',
6
- darkMode && ' dark',
7
- $attrs['wrapperAttrs']?.class
8
- )"
9
- v-bind="{ ...$attrs['wrapperAttrs'], attrs: void 0, class: void 0 }"
5
+ (showOutline ? 'group outlined outlined-visible' : '[&_*]:outline-hidden'),
6
+ darkMode && ' dark',
7
+ ($attrs['wrapperAttrs'] as any)?.class
8
+ )"
9
+ v-bind="{ ...($attrs['wrapperAttrs']), attrs:undefined, class: undefined }"
10
10
  :ref="handleRef"
11
11
  >
12
12
  <!-- id root is useful for teleports, so they are at the topmost level where they can still be styled -->
13
13
  <!-- See TestControls for why the margins here -->
14
14
  <div
15
15
  id="root"
16
- v-bind="{ ...$attrs.attrs, class: void 0, wrapperAttrs: void 0 }"
17
- :class="twMerge(
18
- `
16
+ v-bind="{ ...$attrs.attrs, class: undefined, wrapperAttrs: undefined }"
17
+ :class="twMerge( `
19
18
  dark:bg-fg
20
19
  dark:text-bg
21
20
  bg-bg
22
21
  text-fg
23
22
  `,
24
- testWrapperMode && `
23
+ testWrapperMode && `
25
24
  px-10
26
25
  pb-10
27
26
  `,
28
- !testWrapperMode && `
27
+ !testWrapperMode && `
29
28
  min-h-dvh
30
29
  flex
31
30
  flex-col
32
31
  `,
33
- $attrs.attrs?.class
34
- )"
32
+ ($attrs as any).attrs?.class)"
35
33
  >
36
34
  <TestControls v-if="testWrapperMode" :show-outline="showOutline"/>
37
35
  <Notifications v-if="useNotifications && isClientSide"/>
@@ -40,73 +38,102 @@
40
38
  </div>
41
39
  </template>
42
40
 
43
- <script setup>
44
- import { unreachable } from "@alanscodelog/utils/unreachable.js";
45
- import {} from "metamorphosis";
46
- import { computed, onBeforeUnmount, onMounted, ref, toRaw } from "vue";
47
- import { useAccesibilityOutline } from "../../composables/useAccesibilityOutline.js";
48
- import { useDivideAttrs } from "../../composables/useDivideAttrs.js";
49
- import { useNotificationHandler } from "../../composables/useNotificationHandler.js";
50
- import { useSetupDarkMode } from "../../composables/useSetupDarkMode.js";
51
- import { useSetupI18n } from "../../composables/useSetupI18n.js";
52
- import { useSetupLocale } from "../../composables/useSetupLocale.js";
53
- import { useShowDevOnlyKey } from "../../composables/useShowDevOnlyKey.js";
54
- import { NotificationHandler } from "../../helpers/NotificationHandler.js";
55
- import { theme as defaultTheme } from "../../theme.js";
56
- import { twMerge } from "../../utils/twMerge.js";
57
- import Notifications from "../LibNotifications/LibNotifications.vue";
58
- import TestControls from "../TestControls/TestControls.vue";
59
- const $attrs = useDivideAttrs(["wrapper"]);
60
- defineOptions({ name: "root", inheritAttrs: false, suspensible: false });
61
- const props = defineProps({
62
- theme: { type: Object, required: false, default: void 0 },
63
- outline: { type: Boolean, required: false, default: true },
64
- forceOutline: { type: Boolean, required: false, default: false },
65
- testWrapperMode: { type: Boolean, required: false, default: false },
66
- id: { type: String, required: false, default: "app" },
67
- getRef: { type: Function, required: false, default: void 0 },
68
- isClientSide: { type: Boolean, required: false, default: true },
69
- useBuiltinTranslations: { type: Boolean, required: false, default: true },
70
- useNotifications: { type: Boolean, required: false, default: true },
71
- notificationHandler: { type: Object, required: false, default: void 0 }
72
- });
73
- const el = ref(null);
74
- function handleRef(_) {
75
- if (_ !== null && !(_ instanceof HTMLElement)) unreachable();
76
- el.value = _;
77
- props.getRef?.(_);
41
+ <script setup lang="ts">
42
+ import { unreachable } from "@alanscodelog/utils/unreachable.js"
43
+ import { type Theme } from "metamorphosis"
44
+ import { type ComponentPublicInstance, computed, onBeforeUnmount, onMounted, ref, toRaw } from "vue"
45
+
46
+ import { useAccesibilityOutline } from "../../composables/useAccesibilityOutline.js"
47
+ import { useDivideAttrs } from "../../composables/useDivideAttrs.js"
48
+ import { useNotificationHandler } from "../../composables/useNotificationHandler.js"
49
+ import { useSetupDarkMode } from "../../composables/useSetupDarkMode.js"
50
+ import { useSetupI18n } from "../../composables/useSetupI18n.js"
51
+ import { useSetupLocale } from "../../composables/useSetupLocale.js"
52
+ import { useShowDevOnlyKey } from "../../composables/useShowDevOnlyKey.js"
53
+ import { NotificationHandler } from "../../helpers/NotificationHandler.js"
54
+ import { theme as defaultTheme } from "../../theme.js"
55
+ import { twMerge } from "../../utils/twMerge.js"
56
+ import Notifications from "../LibNotifications/LibNotifications.vue"
57
+ import TestControls from "../TestControls/TestControls.vue"
58
+
59
+ const $attrs = useDivideAttrs(["wrapper"])
60
+
61
+ defineOptions({ name: "root", inheritAttrs: false, suspensible: false })
62
+ const props = withDefaults(defineProps<{
63
+ theme?: Theme
64
+ outline?: boolean
65
+ forceOutline?: boolean
66
+ testWrapperMode?: boolean
67
+ id?: string
68
+ /** You can set a ref to the root element by passing :getRef="_ => el = _" */
69
+ getRef?: (el: HTMLElement | null) => void
70
+ /** True by default, should be passed import.meta.client if using nuxt, or false when running server side. */
71
+ isClientSide?: boolean
72
+ useBuiltinTranslations?: boolean
73
+ useNotifications?: boolean
74
+ notificationHandler?: NotificationHandler
75
+ }>(), {
76
+ theme: undefined,
77
+ testWrapperMode: false,
78
+ outline: true,
79
+ forceOutline: false,
80
+ id: "app",
81
+ getRef: undefined,
82
+ isClientSide: true,
83
+ useBuiltinTranslations: true,
84
+ useNotifications: true,
85
+ notificationHandler: undefined
86
+ })
87
+
88
+ const el = ref<HTMLElement | null>(null)
89
+
90
+ function handleRef(_: Element | ComponentPublicInstance | null): void {
91
+ if (_ !== null && !(_ instanceof HTMLElement)) unreachable()
92
+ el.value = _
93
+ props.getRef?.(_)
78
94
  }
95
+
79
96
  if (props.useNotifications) {
80
- const handler = props.notificationHandler ?? new NotificationHandler();
81
- useNotificationHandler(handler, props.isClientSide);
97
+ const handler = props.notificationHandler ?? new NotificationHandler()
98
+ useNotificationHandler(handler, props.isClientSide)
99
+ }
100
+
101
+ const autoOutline = useAccesibilityOutline(el).outline
102
+
103
+ const showOutline = computed(() => (props.outline && autoOutline.value) || props.forceOutline)
104
+
105
+ const theme = computed(() => props.theme ?? defaultTheme)
106
+ const themeCb = (): void => {
107
+ toRaw(theme.value).attach(el.value!)
82
108
  }
83
- const autoOutline = useAccesibilityOutline(el).outline;
84
- const showOutline = computed(() => props.outline && autoOutline.value || props.forceOutline);
85
- const theme = computed(() => props.theme ?? defaultTheme);
86
- const themeCb = () => {
87
- toRaw(theme.value).attach(el.value);
88
- };
89
109
  if (props.isClientSide) {
90
- onMounted(() => {
91
- toRaw(theme.value).on("change", themeCb);
92
- themeCb();
93
- });
94
- onBeforeUnmount(() => {
95
- toRaw(theme.value).off("change", themeCb);
96
- });
110
+ onMounted(() => {
111
+ toRaw(theme.value).on("change", themeCb)
112
+ themeCb()
113
+ })
114
+ onBeforeUnmount(() => {
115
+ toRaw(theme.value).off("change", themeCb)
116
+ })
97
117
  }
98
- const darkModeSetup = useSetupDarkMode({ isClientSide: props.isClientSide });
99
- const darkMode = darkModeSetup.darkMode;
100
- useShowDevOnlyKey();
118
+
119
+ const darkModeSetup = useSetupDarkMode({ isClientSide: props.isClientSide })
120
+
121
+ const darkMode = darkModeSetup.darkMode
122
+
123
+ useShowDevOnlyKey()
124
+
101
125
  defineExpose({
102
- darkMode: darkModeSetup
103
- });
126
+ darkMode: darkModeSetup,
127
+ })
128
+
104
129
  if (props.useBuiltinTranslations) {
105
- const { languageLocale } = useSetupLocale();
106
- void useSetupI18n({
107
- locale: languageLocale,
108
- useBuiltinTranslations: true,
109
- useDummyMessageSetWhileLoading: true
110
- });
130
+ const { languageLocale } = useSetupLocale()
131
+ void useSetupI18n({
132
+ locale: languageLocale,
133
+ useBuiltinTranslations: true,
134
+ useDummyMessageSetWhileLoading: true,
135
+ })
111
136
  }
137
+
112
138
  </script>
139
+
@@ -0,0 +1,26 @@
1
+ import type { StoryObj } from "@storybook/vue3";
2
+ import * as components from "../index.js.js";
3
+ declare const meta: {
4
+ component: any;
5
+ title: string;
6
+ args: {
7
+ modelValue: string;
8
+ placeholder: string;
9
+ };
10
+ };
11
+ export default meta;
12
+ type Story = StoryObj<typeof components.LibSimpleInput>;
13
+ /** Input */
14
+ export declare const Primary: Story;
15
+ /** Has more reasonable min-width inside a flexbox. */
16
+ export declare const InsideAFlexbox: Story;
17
+ export declare const Disabled: any;
18
+ export declare const Readonly: any;
19
+ export declare const Invalid: any;
20
+ /**
21
+ * Intended for being wrapped.
22
+ * Should not have any border or focus outline styles.
23
+ */
24
+ export declare const Borderless: any;
25
+ export declare const Numerical: any;
26
+ export declare const NumericalInsideAFlexbox: any;