carbon-design-system / carbon-components-svelte

Svelte implementation of the Carbon Design System
https://svelte.carbondesignsystem.com
Apache License 2.0
2.7k stars 261 forks source link

using DatePicker to select month (or other unit) #976

Open TheophileMot opened 2 years ago

TheophileMot commented 2 years ago

It seems that the DatePicker component only allows for selecting a specific day, or a range between two days. Is there a view that shows only months (or other units, like weeks or years)? I would like to be able to select "January 2022" (for example) without having to click on, or see, the days in the month.

metonym commented 2 years ago

Interesting, but would a Dropdown to select a month work for your use case?

TheophileMot commented 2 years ago

No, a Dropdown wouldn't work for my purposes. I dug around, though, and found that the flatpickr library used by the DatePicker actually does have the capability for a month view. It's not part of the default flatpickr object, but is available through a plugin.

I managed to rewrite the DatePicker component in my project to use the plugin; it looks like this:

image

Since this is a special use case, though, maybe in the end it's best not to add it to the main Carbon library?

metonym commented 2 years ago

Got it – feel free to open an issue in the Carbon repo as this definitely seems like a valid use case.

Daniela94 commented 1 year ago

TheophileMot

Hi, I think you did an excellent job, can you tell how did you manage to rewrite DatePicker and add the plugin? I'm stuck with it.

TheophileMot commented 1 year ago

@Daniela94 Sure, there were many small changes, but I can give you an idea. (Keep in mind that It's been over a year, so the Carbon library has surely updated this component in the meantime.)

Find the DatePicker component and copy the folder over into your project; you can then modify DatePicker.svelte, createCalendar.js, and so on.

First, I added "month" as a date picker type:

// DatePicker.svelte

   /**
    * Specify the date picker type
-   * @type {"simple" | "single" | "range"}
+   * @type {"simple" | "single" | "range" | "month"}
    */
   export let datePickerType = 'simple';

   // ...

-  const hasCalendar = derived(mode, _ => _ === 'single' || _ === 'range');
+  const hasCalendar = derived(mode, _ => _ === 'single' || _ === 'range' || _=== 'month');

Then, in the utility file:

// createCalendar.js

   let rangePlugin;
+  let monthSelectPlugin;

   if (options.mode === 'range') {
-    const importee = await import('flatpickr/dist/esm/plugins/rangePlugin');
+    const importee = await import('flatpickr/dist/plugins/rangePlugin');
     rangePlugin = importee.default;
   }

+  if (options.mode === 'month') {
+    const importee = await import('flatpickr/dist/plugins/monthSelect');
+    monthSelectPlugin = importee.default;
+  }

   return new flatpickr(base, {
     allowInput: true,
     disableMobile: true,
     clickOpens: true,
     locale,
-     plugins: [options.mode === 'range' && new rangePlugin({ position: 'left', input })].filter(
-      Boolean
-    ),
+     plugins: [
+      options.mode === 'range' && new rangePlugin({ position: 'left', input }),
+      options.mode === 'month' &&
+        new monthSelectPlugin({
+          shorthand: true, // abbreviate month names to Jan, Feb, etc.
+          altFormat: options.altFormat,
+          dateFormat: options.dateFormat,
+        }),
+    ].filter(Boolean),
     // ...
    onMonthChange: (s, d, instance) => {
-     updateMonthNode(instance);
+     if (options.mode !== 'month') updateMonthNode(instance);
    },
    onOpen: (s, d, instance) => {
      dispatch('open');
      updateClasses(instance);
-     updateMonthNode(instance);      
+     if (options.mode !== 'month') updateMonthNode(instance);
    },

There might be other small details I've missed, but that should get you started. Good luck!