@iota/apps-ui-kit 0.9.5 → 0.10.1

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 (30) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.d.ts +55 -3
  3. package/dist/index.es.js +5697 -6536
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +36 -40
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/style.css +2 -1
  8. package/package.json +14 -18
  9. package/src/lib/components/atoms/badge/Badge.tsx +4 -3
  10. package/src/lib/components/atoms/badge/badge.classes.ts +3 -0
  11. package/src/lib/components/atoms/badge/badge.enums.ts +1 -0
  12. package/src/lib/components/atoms/key-value-info/KeyValueInfo.tsx +1 -1
  13. package/src/lib/components/atoms/label-text/LabelText.tsx +1 -1
  14. package/src/lib/components/atoms/tooltip/Tooltip.tsx +2 -2
  15. package/src/lib/components/molecules/date-picker/DatePicker.tsx +412 -0
  16. package/src/lib/components/molecules/date-picker/date-picker.classes.ts +42 -0
  17. package/src/lib/components/molecules/date-picker/date-picker.constants.ts +23 -0
  18. package/src/lib/components/molecules/date-picker/date-picker.enums.ts +8 -0
  19. package/src/lib/components/molecules/date-picker/date-picker.helpers.ts +67 -0
  20. package/src/lib/components/molecules/date-picker/index.ts +5 -0
  21. package/src/lib/components/molecules/index.ts +1 -0
  22. package/src/lib/styles/components.css +89 -0
  23. package/src/lib/styles/variables/dark-variables.css +15 -0
  24. package/src/lib/styles/variables/light-variables.css +15 -0
  25. package/src/lib/styles/variables/names-variables.css +15 -0
  26. package/src/storybook/stories/design-tokens/{colors.stories.mdx → colors.mdx} +1 -1
  27. package/src/storybook/stories/design-tokens/{icons.stories.mdx → icons.mdx} +1 -1
  28. package/src/storybook/stories/design-tokens/{typeset.stories.mdx → typeset.mdx} +1 -1
  29. package/src/storybook/stories/design-tokens/{variable-spacing.stories.mdx → variable-spacing.mdx} +1 -1
  30. package/src/storybook/stories/molecules/DatePicker.stories.tsx +132 -0
@@ -0,0 +1,67 @@
1
+ // Copyright (c) 2026 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { DECADE_SIZE } from './date-picker.constants';
5
+ import { DatePickerFormat } from './date-picker.enums';
6
+
7
+ export function isSameDay(a: Date, b: Date): boolean {
8
+ return (
9
+ a.getFullYear() === b.getFullYear() &&
10
+ a.getMonth() === b.getMonth() &&
11
+ a.getDate() === b.getDate()
12
+ );
13
+ }
14
+
15
+ export function startOfDay(date: Date): Date {
16
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
17
+ }
18
+
19
+ /** Returns true when date falls outside the [min, max] inclusive range. */
20
+ export function isDateDisabled(date: Date, min?: Date, max?: Date): boolean {
21
+ const d = startOfDay(date);
22
+ if (min && d < startOfDay(min)) return true;
23
+ if (max && d > startOfDay(max)) return true;
24
+ return false;
25
+ }
26
+
27
+ /** Returns true when every day in year is outside [min, max]. */
28
+ export function isYearDisabled(year: number, min?: Date, max?: Date): boolean {
29
+ if (min && new Date(year, 11, 31) < startOfDay(min)) return true;
30
+ if (max && new Date(year, 0, 1) > startOfDay(max)) return true;
31
+ return false;
32
+ }
33
+
34
+ export function formatDate(date: Date, format: DatePickerFormat): string {
35
+ const year = String(date.getFullYear());
36
+ const month = String(date.getMonth() + 1).padStart(2, '0');
37
+ const day = String(date.getDate()).padStart(2, '0');
38
+ switch (format) {
39
+ case DatePickerFormat.DayMonthYear:
40
+ return `${day}/${month}/${year}`;
41
+ case DatePickerFormat.MonthDayYear:
42
+ return `${month}/${day}/${year}`;
43
+ case DatePickerFormat.YearMonthDay:
44
+ return `${year}/${month}/${day}`;
45
+ default:
46
+ return `${day}/${month}/${year}`;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Builds the 6×7 grid of dates for the calendar day view
52
+ * starts on Sunday of the week containing the 1st of the month.
53
+ */
54
+ export function buildCalendarGrid(year: number, month: number): Date[] {
55
+ const firstDay = new Date(year, month, 1);
56
+ const startOffset = firstDay.getDay(); // 0 = Sunday
57
+ const grid: Date[] = [];
58
+ for (let i = -startOffset; i < 42 - startOffset; i++) {
59
+ grid.push(new Date(year, month, 1 + i));
60
+ }
61
+ return grid;
62
+ }
63
+
64
+ /** Returns the first year of the decade that contains year */
65
+ export function decadeStart(year: number): number {
66
+ return Math.floor(year / DECADE_SIZE) * DECADE_SIZE;
67
+ }
@@ -0,0 +1,5 @@
1
+ // Copyright (c) 2026 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export * from './DatePicker';
5
+ export * from './date-picker.enums';
@@ -17,3 +17,4 @@ export * from './search';
17
17
  export * from './card';
18
18
  export * from './display-stats';
19
19
  export * from './visual-asset-card';
20
+ export * from './date-picker';
@@ -26,6 +26,14 @@
26
26
  border-color: var(--badge-border-color-soft);
27
27
  }
28
28
 
29
+ .badge-border-color-outlined {
30
+ border-color: theme('colors.iota-neutral.40');
31
+ }
32
+
33
+ .badge-ring-outlined {
34
+ box-shadow: inset 0 0 0 1px theme('colors.iota-neutral.40');
35
+ }
36
+
29
37
  .badge-text-color-neutral {
30
38
  color: var(--badge-text-color-neutral);
31
39
  }
@@ -724,6 +732,87 @@
724
732
  color: var(--table-text-color);
725
733
  }
726
734
 
735
+ /* DATE PICKER */
736
+ .date-picker-trigger-text-color {
737
+ color: var(--date-picker-text-color);
738
+ }
739
+
740
+ .date-picker-trigger-placeholder-color {
741
+ color: var(--date-picker-trigger-placeholder-color);
742
+ }
743
+
744
+ .date-picker-trigger-border-color {
745
+ border-color: var(--date-picker-border-color);
746
+ }
747
+
748
+ .date-picker-trigger-border-hover-color {
749
+ border-color: var(--date-picker-trigger-border-hover-color);
750
+ }
751
+
752
+ .date-picker-trigger-border-focus-color {
753
+ border-color: var(--date-picker-focus-color);
754
+ }
755
+
756
+ .date-picker-trigger-border-error-color {
757
+ border-color: var(--date-picker-trigger-border-error-color);
758
+ }
759
+
760
+ .date-picker-calendar-bg {
761
+ background-color: var(--date-picker-calendar-bg);
762
+ }
763
+
764
+ .date-picker-calendar-border-color {
765
+ border-color: var(--date-picker-border-color);
766
+ }
767
+
768
+ .date-picker-header-text-color {
769
+ color: var(--date-picker-text-color);
770
+ }
771
+
772
+ .date-picker-nav-icon-color {
773
+ color: var(--date-picker-muted-text-color);
774
+ }
775
+
776
+ .date-picker-nav-bg-hover:enabled:hover {
777
+ background-color: var(--date-picker-hover-bg);
778
+ }
779
+
780
+ .date-picker-weekday-text-color {
781
+ color: var(--date-picker-muted-text-color);
782
+ }
783
+
784
+ .date-picker-day-text-color {
785
+ color: var(--date-picker-text-color);
786
+ }
787
+
788
+ .date-picker-day-bg-hover:enabled:hover {
789
+ background-color: var(--date-picker-hover-bg);
790
+ }
791
+
792
+ .date-picker-day-text-color-hover:enabled:hover {
793
+ color: var(--date-picker-text-color);
794
+ }
795
+
796
+ .date-picker-day-bg-selected {
797
+ background-color: var(--date-picker-day-bg-selected);
798
+ }
799
+
800
+ .date-picker-day-text-selected {
801
+ color: var(--date-picker-day-text-selected);
802
+ }
803
+
804
+ .date-picker-day-today-ring {
805
+ box-shadow: inset 0 0 0 1.5px var(--date-picker-focus-color);
806
+ }
807
+
808
+ .date-picker-day-text-disabled {
809
+ color: var(--date-picker-day-text-disabled);
810
+ }
811
+
812
+ .date-picker-day-text-outside-month {
813
+ color: var(--date-picker-day-text-outside-month);
814
+ }
815
+
727
816
  /* DIALOG */
728
817
  .dialog-outline {
729
818
  outline: var(--dialog-outline);
@@ -256,6 +256,21 @@
256
256
  /* TABLE */
257
257
  --table-text-color: theme('colors.iota-neutral.60');
258
258
 
259
+ /* DATE PICKER */
260
+ --date-picker-text-color: theme('colors.iota-neutral.92');
261
+ --date-picker-trigger-placeholder-color: rgba(136, 146, 161, 0.4);
262
+ --date-picker-border-color: theme('colors.iota-neutral.20');
263
+ --date-picker-trigger-border-hover-color: theme('colors.iota-neutral.60');
264
+ --date-picker-focus-color: theme('colors.iota-primary.80');
265
+ --date-picker-trigger-border-error-color: theme('colors.iota-error.80');
266
+ --date-picker-calendar-bg: theme('colors.iota-neutral.6');
267
+ --date-picker-muted-text-color: theme('colors.iota-neutral.60');
268
+ --date-picker-hover-bg: theme('colors.iota-neutral.12');
269
+ --date-picker-day-bg-selected: theme('colors.iota-primary.30');
270
+ --date-picker-day-text-selected: theme('colors.iota-primary.100');
271
+ --date-picker-day-text-disabled: theme('colors.iota-neutral.60');
272
+ --date-picker-day-text-outside-month: theme('colors.iota-neutral.40');
273
+
259
274
  /* DIALOG */
260
275
  --dialog-outline: none;
261
276
  --dialog-overlay-bg: theme('colors.shader-neutral-light.48');
@@ -270,6 +270,21 @@
270
270
  /* TABLE */
271
271
  --table-text-color: theme('colors.iota-neutral.40');
272
272
 
273
+ /* DATE PICKER */
274
+ --date-picker-text-color: theme('colors.iota-neutral.10');
275
+ --date-picker-trigger-placeholder-color: rgba(84, 94, 110, 0.4);
276
+ --date-picker-border-color: theme('colors.iota-neutral.80');
277
+ --date-picker-trigger-border-hover-color: theme('colors.iota-neutral.50');
278
+ --date-picker-focus-color: theme('colors.iota-primary.30');
279
+ --date-picker-trigger-border-error-color: theme('colors.iota-error.30');
280
+ --date-picker-calendar-bg: theme('colors.iota-neutral.100');
281
+ --date-picker-muted-text-color: theme('colors.iota-neutral.40');
282
+ --date-picker-hover-bg: theme('colors.iota-neutral.92');
283
+ --date-picker-day-bg-selected: theme('colors.iota-primary.30');
284
+ --date-picker-day-text-selected: theme('colors.iota-primary.100');
285
+ --date-picker-day-text-disabled: theme('colors.iota-neutral.40');
286
+ --date-picker-day-text-outside-month: theme('colors.iota-neutral.60');
287
+
273
288
  /* DIALOG */
274
289
  --dialog-outline: none;
275
290
  --dialog-overlay-bg: theme('colors.shader-neutral-light.48');
@@ -267,4 +267,19 @@
267
267
 
268
268
  /* TABLE */
269
269
  --table-text-color: theme('colors.names-neutral.70');
270
+
271
+ /* DATE PICKER */
272
+ --date-picker-text-color: theme('colors.names-neutral.92');
273
+ --date-picker-trigger-placeholder-color: rgba(136, 146, 161, 0.4);
274
+ --date-picker-border-color: theme('colors.names-neutral.20');
275
+ --date-picker-trigger-border-hover-color: theme('colors.names-neutral.60');
276
+ --date-picker-focus-color: theme('colors.names-primary.80');
277
+ --date-picker-trigger-border-error-color: theme('colors.names-error.80');
278
+ --date-picker-calendar-bg: theme('colors.names-neutral.6');
279
+ --date-picker-muted-text-color: theme('colors.names-neutral.70');
280
+ --date-picker-hover-bg: theme('colors.names-neutral.12');
281
+ --date-picker-day-bg-selected: theme('colors.names-primary.30');
282
+ --date-picker-day-text-selected: theme('colors.names-primary.100');
283
+ --date-picker-day-text-disabled: theme('colors.names-neutral.60');
284
+ --date-picker-day-text-outside-month: theme('colors.names-neutral.40');
270
285
  }
@@ -1,4 +1,4 @@
1
- import { Meta, ColorPalette, ColorItem } from '@storybook/blocks';
1
+ import { Meta, ColorPalette, ColorItem } from '@storybook/addon-docs/blocks';
2
2
  import {
3
3
  IOTA_PRIMITIVES_COLOR_PALETTE,
4
4
  IOTA_NAMES_COLOR_PALETTE,
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Meta, Title, IconGallery, IconItem } from '@storybook/blocks';
2
+ import { Meta, Title, IconGallery, IconItem } from '@storybook/addon-docs/blocks';
3
3
  import * as Icons from '@iota/apps-ui-icons';
4
4
  import { DocsSyncTheme } from '../components';
5
5
 
@@ -1,4 +1,4 @@
1
- import { Meta, Typeset, Unstyled } from '@storybook/blocks';
1
+ import { Meta, Typeset, Unstyled } from '@storybook/addon-docs/blocks';
2
2
  import { TYPESETS } from '../../constants';
3
3
  import { TypeSet, TypeSetItem } from '../../blocks';
4
4
  import { DocsSyncTheme } from '../components';
@@ -1,4 +1,4 @@
1
- import { Meta, Typeset, Unstyled } from '@storybook/blocks';
1
+ import { Meta, Typeset, Unstyled } from '@storybook/addon-docs/blocks';
2
2
  import { VariableSpacingShowcase, DocsSyncTheme } from '../components';
3
3
 
4
4
  <DocsSyncTheme />
@@ -0,0 +1,132 @@
1
+ // Copyright (c) 2026 IOTA Stiftung
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { Meta, StoryObj } from '@storybook/react';
5
+ import { useState } from 'react';
6
+ import { DatePicker, DatePickerFormat } from '@/components/molecules/date-picker';
7
+
8
+ const meta: Meta<typeof DatePicker> = {
9
+ component: DatePicker,
10
+ tags: ['autodocs'],
11
+ parameters: {
12
+ layout: 'centered',
13
+ },
14
+ argTypes: {
15
+ dateFormat: {
16
+ control: { type: 'select' },
17
+ options: Object.values(DatePickerFormat),
18
+ },
19
+ },
20
+ } satisfies Meta<typeof DatePicker>;
21
+
22
+ export default meta;
23
+
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ export const Default: Story = {
27
+ args: {
28
+ label: 'Select Date',
29
+ caption: 'Choose a date from the calendar',
30
+ placeholder: 'DD/MM/YYYY',
31
+ dateFormat: DatePickerFormat.DayMonthYear,
32
+ },
33
+ render: (args) => {
34
+ const [date, setDate] = useState<Date | undefined>(undefined);
35
+ return (
36
+ <div className="w-72 pb-80">
37
+ <DatePicker {...args} value={date} onChange={setDate} />
38
+ </div>
39
+ );
40
+ },
41
+ };
42
+
43
+ export const WithDateFormat: Story = {
44
+ args: {
45
+ label: 'Format DD/MM/YYYY',
46
+ caption: 'Change the date format from the controls ',
47
+ dateFormat: DatePickerFormat.DayMonthYear,
48
+ },
49
+ render: (args) => {
50
+ const [date, setDate] = useState<Date | undefined>(new Date(2026, 3, 15));
51
+ return (
52
+ <div className="w-72 pb-80">
53
+ <DatePicker {...args} value={date} onChange={setDate} />
54
+ </div>
55
+ );
56
+ },
57
+ };
58
+
59
+ export const WithMinMaxLimitsInclusive: Story = {
60
+ name: 'Min & Max (inclusive)',
61
+ args: {
62
+ label: 'April 2026 only',
63
+ caption: 'Min = Apr 1 · Max = Apr 30 · both selectable',
64
+ dateFormat: DatePickerFormat.DayMonthYear,
65
+ },
66
+ render: (args) => {
67
+ const minDate = new Date(2026, 3, 1); // April 1 2026
68
+ const maxDate = new Date(2026, 3, 30); // April 30 2026
69
+ const [date, setDate] = useState<Date | undefined>(undefined);
70
+ return (
71
+ <div className="w-72 pb-80">
72
+ <DatePicker
73
+ {...args}
74
+ value={date}
75
+ onChange={setDate}
76
+ minDate={minDate}
77
+ maxDate={maxDate}
78
+ />
79
+ </div>
80
+ );
81
+ },
82
+ };
83
+
84
+ export const YearPickerNavigation: Story = {
85
+ name: 'Year picker (click "Month Year")',
86
+ args: {
87
+ label: 'Birth date',
88
+ caption: 'Click "April 2026" header to jump to any year',
89
+ dateFormat: DatePickerFormat.DayMonthYear,
90
+ },
91
+ render: (args) => {
92
+ const [date, setDate] = useState<Date | undefined>(undefined);
93
+ return (
94
+ <div className="w-72 pb-80">
95
+ <DatePicker {...args} value={date} onChange={setDate} />
96
+ </div>
97
+ );
98
+ },
99
+ };
100
+
101
+ export const WithError: Story = {
102
+ args: {
103
+ label: 'Expiry Date',
104
+ errorMessage: 'Date is required',
105
+ placeholder: 'DD/MM/YYYY',
106
+ dateFormat: DatePickerFormat.DayMonthYear,
107
+ },
108
+ render: (args) => {
109
+ const [date, setDate] = useState<Date | undefined>(undefined);
110
+ return (
111
+ <div className="w-72 pb-80">
112
+ <DatePicker {...args} value={date} onChange={setDate} />
113
+ </div>
114
+ );
115
+ },
116
+ };
117
+
118
+ export const Disabled: Story = {
119
+ args: {
120
+ label: 'Locked Date',
121
+ caption: 'This field is disabled',
122
+ disabled: true,
123
+ dateFormat: DatePickerFormat.DayMonthYear,
124
+ },
125
+ render: (args) => {
126
+ return (
127
+ <div className="w-72">
128
+ <DatePicker {...args} value={new Date(2026, 0, 1)} />
129
+ </div>
130
+ );
131
+ },
132
+ };