@db-vincent/components 0.1.0 → 0.1.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 (66) hide show
  1. package/package.json +3 -3
  2. package/src/astro/Avatar.astro +88 -0
  3. package/src/astro/AvatarGroup.astro +63 -0
  4. package/src/astro/Chip.astro +22 -3
  5. package/src/astro/Drawer.astro +30 -0
  6. package/src/astro/Grid.astro +7 -1
  7. package/src/astro/GridItem.astro +3 -1
  8. package/src/astro/Menu.astro +151 -0
  9. package/src/astro/MenuItem.astro +57 -0
  10. package/src/astro/Modal.astro +10 -3
  11. package/src/astro/Pagination.astro +82 -32
  12. package/src/astro/Popover.astro +51 -0
  13. package/src/astro/Progress.astro +71 -0
  14. package/src/astro/Select.astro +211 -194
  15. package/src/astro/Skeleton.astro +4 -2
  16. package/src/astro/Spinner.astro +1 -0
  17. package/src/astro/Stepper.astro +82 -0
  18. package/src/astro/Switch.astro +78 -0
  19. package/src/astro/Table.astro +90 -76
  20. package/src/astro/Tabs.astro +83 -0
  21. package/src/astro/TextField.astro +100 -82
  22. package/src/astro/Toast.astro +1 -1
  23. package/src/astro/Tooltip.astro +54 -0
  24. package/src/data/icons.ts +16 -0
  25. package/src/scripts/avatar.ts +33 -0
  26. package/src/scripts/menu.ts +218 -0
  27. package/src/scripts/tabs.ts +127 -0
  28. package/src/scripts/toast.ts +45 -11
  29. package/src/scripts/tooltip.ts +127 -0
  30. package/src/styles/accordion.css +2 -0
  31. package/src/styles/alert.css +2 -0
  32. package/src/styles/avatar.css +131 -0
  33. package/src/styles/badge.css +2 -0
  34. package/src/styles/base.css +2 -0
  35. package/src/styles/breadcrumbs.css +2 -0
  36. package/src/styles/button.css +13 -2
  37. package/src/styles/card.css +8 -4
  38. package/src/styles/chip.css +2 -0
  39. package/src/styles/choice.css +8 -2
  40. package/src/styles/code.css +2 -0
  41. package/src/styles/empty.css +2 -0
  42. package/src/styles/example.css +2 -0
  43. package/src/styles/grid.css +2 -0
  44. package/src/styles/input.css +11 -1
  45. package/src/styles/menu.css +151 -0
  46. package/src/styles/modal.css +169 -27
  47. package/src/styles/motion.css +21 -3
  48. package/src/styles/nav.css +2 -0
  49. package/src/styles/navbar.css +2 -0
  50. package/src/styles/page-header.css +3 -0
  51. package/src/styles/pagination.css +4 -0
  52. package/src/styles/popover.css +134 -0
  53. package/src/styles/progress.css +95 -0
  54. package/src/styles/section.css +2 -0
  55. package/src/styles/select.css +12 -1
  56. package/src/styles/skeleton.css +2 -0
  57. package/src/styles/spinner.css +2 -0
  58. package/src/styles/sr-only.css +14 -0
  59. package/src/styles/stepper.css +169 -0
  60. package/src/styles/switch.css +143 -0
  61. package/src/styles/table.css +2 -0
  62. package/src/styles/tabs.css +120 -0
  63. package/src/styles/theme-toggle.css +2 -0
  64. package/src/styles/toast.css +41 -23
  65. package/src/styles/tooltip.css +63 -0
  66. package/src/styles/topbar.css +2 -0
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer motion {
2
4
  .ds-motion-lift,
3
5
  .ds-motion-underline,
@@ -31,12 +33,18 @@
31
33
  var(--ds-motion-delay);
32
34
  }
33
35
 
34
- .ds-motion-lift:hover,
35
36
  .ds-motion-lift:focus-visible {
36
37
  box-shadow: var(--motion-lift-shadow);
37
38
  transform: translateY(var(--motion-lift-y));
38
39
  }
39
40
 
41
+ @media (hover: hover) and (pointer: fine) {
42
+ .ds-motion-lift:hover {
43
+ box-shadow: var(--motion-lift-shadow);
44
+ transform: translateY(var(--motion-lift-y));
45
+ }
46
+ }
47
+
40
48
  .ds-motion-underline {
41
49
  background-image: linear-gradient(currentColor, currentColor);
42
50
  background-position: 0 100%;
@@ -66,11 +74,16 @@
66
74
  var(--ds-motion-delay);
67
75
  }
68
76
 
69
- .ds-motion-arrow:hover .ds-motion-arrow__target,
70
77
  .ds-motion-arrow:focus-visible .ds-motion-arrow__target {
71
78
  transform: translateX(var(--motion-nudge));
72
79
  }
73
80
 
81
+ @media (hover: hover) and (pointer: fine) {
82
+ .ds-motion-arrow:hover .ds-motion-arrow__target {
83
+ transform: translateX(var(--motion-nudge));
84
+ }
85
+ }
86
+
74
87
  .ds-motion-row {
75
88
  transition:
76
89
  background-color var(--ds-motion-time) var(--motion-ease)
@@ -78,11 +91,16 @@
78
91
  transform var(--ds-motion-time) var(--motion-ease) var(--ds-motion-delay);
79
92
  }
80
93
 
81
- .ds-motion-row:hover,
82
94
  .ds-motion-row:focus-within {
83
95
  transform: translateX(var(--motion-row-nudge));
84
96
  }
85
97
 
98
+ @media (hover: hover) and (pointer: fine) {
99
+ .ds-motion-row:hover {
100
+ transform: translateX(var(--motion-row-nudge));
101
+ }
102
+ }
103
+
86
104
  @media (prefers-reduced-motion: reduce) {
87
105
  .ds-motion-lift:hover,
88
106
  .ds-motion-lift:focus-visible,
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-nav {
3
5
  background: var(--nav-bg);
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  /* The bar is a query container: it collapses by its own width, so it works
3
5
  the same as a page header, inside a split view or in a demo frame. */
@@ -1,7 +1,10 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-page-header {
3
5
  display: grid;
4
6
  gap: var(--page-header-gap);
7
+ grid-template-columns: minmax(0, 1fr);
5
8
  }
6
9
 
7
10
  .ds-page-header__title {
@@ -1,13 +1,17 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-pagination {
3
5
  align-items: center;
4
6
  display: flex;
7
+ flex-wrap: wrap;
5
8
  gap: var(--pagination-gap);
6
9
  }
7
10
 
8
11
  .ds-pagination__list {
9
12
  align-items: center;
10
13
  display: flex;
14
+ flex-wrap: wrap;
11
15
  gap: var(--pagination-gap);
12
16
  list-style: none;
13
17
  margin: 0;
@@ -0,0 +1,134 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ @layer components {
4
+ /* Wraps a trigger and its anchored surface. Each wrapper scopes the anchor
5
+ name, so any number of popovers, menus and tooltips can share it. */
6
+ .ds-anchor {
7
+ anchor-name: --ds-anchor;
8
+ anchor-scope: --ds-anchor;
9
+ display: inline-flex;
10
+ }
11
+
12
+ .ds-popover {
13
+ --ds-anchor-gap: var(--popover-gap);
14
+
15
+ background: var(--popover-bg);
16
+ border: 1px solid var(--popover-border);
17
+ border-radius: var(--popover-radius);
18
+ box-shadow: var(--popover-shadow);
19
+ color: var(--popover-fg);
20
+ font-size: var(--text-sm);
21
+ line-height: var(--leading-sm);
22
+ max-width: min(var(--popover-max-width), calc(100vw - var(--space-8)));
23
+ opacity: 0;
24
+ overflow: auto;
25
+ padding: var(--popover-padding);
26
+ transform: scale(var(--popover-scale-from));
27
+ transform-origin: top center;
28
+ transition:
29
+ opacity var(--popover-duration-exit) var(--popover-ease-exit),
30
+ transform var(--popover-duration-exit) var(--popover-ease-exit),
31
+ display var(--popover-duration-exit) allow-discrete,
32
+ overlay var(--popover-duration-exit) allow-discrete;
33
+ }
34
+
35
+ .ds-popover:popover-open {
36
+ opacity: 1;
37
+ transform: none;
38
+ transition:
39
+ opacity var(--popover-duration-enter) var(--popover-ease-enter),
40
+ transform var(--popover-duration-enter) var(--popover-ease-enter),
41
+ display var(--popover-duration-enter) allow-discrete,
42
+ overlay var(--popover-duration-enter) allow-discrete;
43
+ }
44
+
45
+ /* Set by script when the surface opens from the keyboard. */
46
+ .ds-popover[data-instant]:popover-open {
47
+ transition-duration: 0s;
48
+ }
49
+
50
+ @starting-style {
51
+ .ds-popover:popover-open {
52
+ opacity: 0;
53
+ transform: scale(var(--popover-scale-from));
54
+ }
55
+ }
56
+
57
+ /* Anchor positioning. Every surface carries a placement modifier. Without
58
+ support the native popover stays centred in the viewport, which is still
59
+ usable. */
60
+ @supports (position-area: block-end) {
61
+ .ds-popover,
62
+ .ds-tooltip {
63
+ /* Centre on the anchor but never past the viewport edge. Held in a
64
+ variable because the CSS validator predates `safe anchor-center`. */
65
+ --ds-anchor-center: safe anchor-center;
66
+
67
+ inset: auto;
68
+ margin: 0;
69
+ position-anchor: --ds-anchor;
70
+ }
71
+
72
+ .ds-popover--bottom,
73
+ .ds-popover--top,
74
+ .ds-tooltip--bottom,
75
+ .ds-tooltip--top {
76
+ justify-self: var(--ds-anchor-center);
77
+ position-try-fallbacks: flip-block;
78
+ }
79
+
80
+ .ds-popover--bottom,
81
+ .ds-tooltip--bottom {
82
+ margin-block-start: var(--ds-anchor-gap);
83
+ position-area: block-end;
84
+ transform-origin: top center;
85
+ }
86
+
87
+ .ds-popover--top,
88
+ .ds-tooltip--top {
89
+ margin-block-end: var(--ds-anchor-gap);
90
+ position-area: block-start;
91
+ transform-origin: bottom center;
92
+ }
93
+
94
+ .ds-popover--start,
95
+ .ds-popover--end,
96
+ .ds-tooltip--start,
97
+ .ds-tooltip--end {
98
+ align-self: var(--ds-anchor-center);
99
+ position-try-fallbacks: flip-inline;
100
+ }
101
+
102
+ .ds-popover--start,
103
+ .ds-tooltip--start {
104
+ margin-inline-end: var(--ds-anchor-gap);
105
+ position-area: inline-start;
106
+ transform-origin: right center;
107
+ }
108
+
109
+ .ds-popover--end,
110
+ .ds-tooltip--end {
111
+ margin-inline-start: var(--ds-anchor-gap);
112
+ position-area: inline-end;
113
+ transform-origin: left center;
114
+ }
115
+ }
116
+
117
+ @media (prefers-reduced-motion: reduce) {
118
+ .ds-popover,
119
+ .ds-popover:popover-open {
120
+ transform: none;
121
+ transition:
122
+ opacity var(--popover-duration-reduced) var(--popover-ease-exit),
123
+ display var(--popover-duration-reduced) allow-discrete,
124
+ overlay var(--popover-duration-reduced) allow-discrete;
125
+ }
126
+
127
+ @starting-style {
128
+ .ds-popover:popover-open {
129
+ opacity: 0;
130
+ transform: none;
131
+ }
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,95 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ @layer components {
4
+ .ds-progress {
5
+ --ds-progress-height: var(--progress-height-md);
6
+ --ds-progress-fill: var(--progress-accent);
7
+ display: grid;
8
+ gap: var(--progress-gap);
9
+ width: 100%;
10
+ }
11
+
12
+ .ds-progress--sm {
13
+ --ds-progress-height: var(--progress-height-sm);
14
+ }
15
+
16
+ .ds-progress--success {
17
+ --ds-progress-fill: var(--progress-success);
18
+ }
19
+
20
+ .ds-progress--warning {
21
+ --ds-progress-fill: var(--progress-warning);
22
+ }
23
+
24
+ .ds-progress--danger {
25
+ --ds-progress-fill: var(--progress-danger);
26
+ }
27
+
28
+ .ds-progress__head {
29
+ align-items: baseline;
30
+ display: flex;
31
+ font-size: var(--progress-font-size);
32
+ gap: var(--space-3);
33
+ justify-content: space-between;
34
+ line-height: var(--leading-sm);
35
+ }
36
+
37
+ .ds-progress__label {
38
+ color: var(--progress-label-fg);
39
+ font-weight: var(--weight-medium);
40
+ }
41
+
42
+ .ds-progress__value {
43
+ color: var(--progress-value-fg);
44
+ font-family: var(--progress-value-font);
45
+ font-size: var(--text-xs);
46
+ font-variant-numeric: tabular-nums;
47
+ }
48
+
49
+ .ds-progress__track {
50
+ background: var(--progress-track);
51
+ border-radius: var(--progress-radius);
52
+ height: var(--ds-progress-height);
53
+ overflow: hidden;
54
+ }
55
+
56
+ .ds-progress__bar {
57
+ background: var(--ds-progress-fill);
58
+ border-radius: var(--progress-radius);
59
+ height: 100%;
60
+ transform: scaleX(var(--ds-progress-value, 0));
61
+ transform-origin: left;
62
+ transition: transform var(--progress-duration) var(--progress-ease);
63
+ width: 100%;
64
+ }
65
+
66
+ .ds-progress--indeterminate .ds-progress__bar {
67
+ animation: ds-progress-slide var(--progress-indeterminate-duration)
68
+ var(--progress-ease) infinite;
69
+ transform: none;
70
+ transition: none;
71
+ width: var(--progress-indeterminate-width);
72
+ }
73
+
74
+ @keyframes ds-progress-slide {
75
+ from {
76
+ transform: translateX(-100%);
77
+ }
78
+
79
+ to {
80
+ transform: translateX(var(--progress-indeterminate-travel));
81
+ }
82
+ }
83
+
84
+ @media (prefers-reduced-motion: reduce) {
85
+ .ds-progress__bar {
86
+ transition: none;
87
+ }
88
+
89
+ .ds-progress--indeterminate .ds-progress__bar {
90
+ animation: none;
91
+ background: var(--progress-indicator-static);
92
+ width: 100%;
93
+ }
94
+ }
95
+ }
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-section {
3
5
  border-top: 1px solid var(--section-border);
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-select {
3
5
  position: relative;
@@ -39,7 +41,7 @@
39
41
  box-shadow:
40
42
  0 0 0 var(--select-focus-width) var(--select-focus-offset-color),
41
43
  0 0 0 calc(var(--select-focus-width) * 2) var(--select-border-focus);
42
- outline: none;
44
+ outline: 2px solid transparent;
43
45
  }
44
46
 
45
47
  .ds-select__control:disabled {
@@ -106,7 +108,16 @@
106
108
  padding: var(--select-popup-padding);
107
109
  position: absolute;
108
110
  top: calc(100% + var(--select-popup-gap));
111
+ transform-origin: top center;
109
112
  z-index: var(--select-popup-z);
113
+ animation: ds-select-in var(--duration-base) var(--ease-enter);
114
+ }
115
+
116
+ @keyframes ds-select-in {
117
+ from {
118
+ opacity: 0;
119
+ transform: translateY(calc(-1 * var(--space-1))) scale(0.97);
120
+ }
110
121
  }
111
122
 
112
123
  .ds-select__popup[hidden] {
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-skeleton {
3
5
  background: var(--skeleton-bg);
@@ -1,3 +1,5 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
1
3
  @layer components {
2
4
  .ds-spinner {
3
5
  border: var(--spinner-stroke) solid var(--spinner-track);
@@ -0,0 +1,14 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ /* Visually hidden, still announced. Shared so components that emit
4
+ .ds-sr-only do not depend on base.css being loaded. */
5
+ @layer components {
6
+ .ds-sr-only {
7
+ clip-path: inset(50%);
8
+ height: 1px;
9
+ overflow: hidden;
10
+ position: absolute;
11
+ white-space: nowrap;
12
+ width: 1px;
13
+ }
14
+ }
@@ -0,0 +1,169 @@
1
+ @layer reset, tokens, base, components, motion, utilities;
2
+
3
+ @layer components {
4
+ .ds-stepper {
5
+ display: grid;
6
+ grid-auto-columns: minmax(0, 1fr);
7
+ grid-auto-flow: column;
8
+ list-style: none;
9
+ margin: 0;
10
+ padding: 0;
11
+ width: 100%;
12
+ }
13
+
14
+ .ds-stepper__item {
15
+ --ds-stepper-marker-bg: var(--stepper-marker-bg-upcoming);
16
+ --ds-stepper-marker-border: var(--stepper-marker-border-upcoming);
17
+ --ds-stepper-marker-fg: var(--stepper-marker-fg-upcoming);
18
+ --ds-stepper-label-fg: var(--stepper-label-fg-upcoming);
19
+ --ds-stepper-description-fg: var(--stepper-description-fg);
20
+ --ds-stepper-connector: var(--stepper-connector-bg);
21
+
22
+ align-content: start;
23
+ display: grid;
24
+ grid-template-columns: auto minmax(0, 1fr);
25
+ }
26
+
27
+ .ds-stepper__item[data-state="current"] {
28
+ --ds-stepper-marker-bg: var(--stepper-marker-bg-current);
29
+ --ds-stepper-marker-border: var(--stepper-marker-border-current);
30
+ --ds-stepper-marker-fg: var(--stepper-marker-fg-current);
31
+ --ds-stepper-label-fg: var(--stepper-label-fg);
32
+ }
33
+
34
+ .ds-stepper__item[data-state="complete"] {
35
+ --ds-stepper-marker-bg: var(--stepper-marker-bg-complete);
36
+ --ds-stepper-marker-border: var(--stepper-marker-border-complete);
37
+ --ds-stepper-marker-fg: var(--stepper-marker-fg-complete);
38
+ --ds-stepper-label-fg: var(--stepper-label-fg);
39
+ --ds-stepper-connector: var(--stepper-connector-bg-complete);
40
+ }
41
+
42
+ .ds-stepper__item[data-state="error"] {
43
+ --ds-stepper-marker-bg: var(--stepper-marker-bg-error);
44
+ --ds-stepper-marker-border: var(--stepper-marker-border-error);
45
+ --ds-stepper-marker-fg: var(--stepper-marker-fg-error);
46
+ --ds-stepper-label-fg: var(--stepper-label-fg-error);
47
+ --ds-stepper-description-fg: var(--stepper-description-fg-error);
48
+ }
49
+
50
+ .ds-stepper__marker {
51
+ align-items: center;
52
+ background: var(--ds-stepper-marker-bg);
53
+ border: var(--stepper-marker-border-width) solid
54
+ var(--ds-stepper-marker-border);
55
+ border-radius: var(--radius-full);
56
+ box-sizing: border-box;
57
+ color: var(--ds-stepper-marker-fg);
58
+ display: inline-flex;
59
+ font-family: var(--stepper-marker-font);
60
+ font-size: var(--stepper-marker-font-size);
61
+ font-variant-numeric: tabular-nums;
62
+ grid-column: 1;
63
+ grid-row: 1;
64
+ height: var(--stepper-marker-size);
65
+ justify-content: center;
66
+ line-height: 1;
67
+ transition:
68
+ background-color var(--stepper-duration) var(--stepper-ease),
69
+ border-color var(--stepper-duration) var(--stepper-ease),
70
+ color var(--stepper-duration) var(--stepper-ease);
71
+ width: var(--stepper-marker-size);
72
+ }
73
+
74
+ .ds-stepper__item::after {
75
+ background: var(--ds-stepper-connector);
76
+ content: "";
77
+ transition: background-color var(--stepper-duration) var(--stepper-ease);
78
+ }
79
+
80
+ .ds-stepper__item:last-child::after {
81
+ display: none;
82
+ }
83
+
84
+ .ds-stepper__body {
85
+ display: grid;
86
+ gap: var(--space-0-5);
87
+ grid-column: 1 / -1;
88
+ grid-row: 2;
89
+ min-width: 0;
90
+ padding-block-start: var(--stepper-gap);
91
+ }
92
+
93
+ .ds-stepper__label {
94
+ color: var(--ds-stepper-label-fg);
95
+ font-size: var(--type-label-size);
96
+ font-weight: var(--type-label-weight);
97
+ letter-spacing: var(--type-label-tracking);
98
+ line-height: var(--type-label-leading);
99
+ overflow-wrap: anywhere;
100
+ transition: color var(--stepper-duration) var(--stepper-ease);
101
+ }
102
+
103
+ .ds-stepper__item[data-state="current"] .ds-stepper__label {
104
+ font-weight: var(--weight-semibold);
105
+ }
106
+
107
+ .ds-stepper__description {
108
+ color: var(--ds-stepper-description-fg);
109
+ font-size: var(--type-caption-size);
110
+ line-height: var(--type-caption-leading);
111
+ overflow-wrap: anywhere;
112
+ transition: color var(--stepper-duration) var(--stepper-ease);
113
+ }
114
+
115
+ /* Horizontal: the connector runs along the marker's row to the next step. */
116
+ .ds-stepper:not(.ds-stepper--vertical) .ds-stepper__item::after {
117
+ align-self: center;
118
+ block-size: var(--stepper-connector-size);
119
+ grid-column: 2;
120
+ grid-row: 1;
121
+ margin-inline: var(--stepper-connector-gap);
122
+ }
123
+
124
+ .ds-stepper:not(.ds-stepper--vertical) .ds-stepper__body {
125
+ padding-inline-end: var(--stepper-connector-gap);
126
+ }
127
+
128
+ .ds-stepper--vertical {
129
+ grid-auto-columns: auto;
130
+ grid-auto-flow: row;
131
+ }
132
+
133
+ .ds-stepper--vertical .ds-stepper__item {
134
+ column-gap: var(--stepper-gap);
135
+ grid-template-rows: auto 1fr;
136
+ }
137
+
138
+ /* Vertical: the body sits beside the marker; the connector drops below it
139
+ and stretches with the body. */
140
+ .ds-stepper--vertical .ds-stepper__body {
141
+ grid-column: 2;
142
+ grid-row: 1 / span 2;
143
+ padding-block-end: var(--stepper-step-gap);
144
+ padding-block-start: calc(
145
+ (var(--stepper-marker-size) - var(--type-label-leading)) / 2
146
+ );
147
+ }
148
+
149
+ .ds-stepper--vertical .ds-stepper__item:last-child .ds-stepper__body {
150
+ padding-block-end: 0;
151
+ }
152
+
153
+ .ds-stepper--vertical .ds-stepper__item::after {
154
+ grid-column: 1;
155
+ grid-row: 2;
156
+ inline-size: var(--stepper-connector-size);
157
+ justify-self: center;
158
+ margin-block: var(--stepper-connector-gap);
159
+ }
160
+
161
+ @media (prefers-reduced-motion: reduce) {
162
+ .ds-stepper__marker,
163
+ .ds-stepper__item::after,
164
+ .ds-stepper__label,
165
+ .ds-stepper__description {
166
+ transition: none;
167
+ }
168
+ }
169
+ }