Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit c9a2324

Browse files
committed
feat(calendar): add clickable arrow button and placeholder
1 parent 24ae0fa commit c9a2324

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

src/components/calendar/datePicker.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
// PRE RELEASE
55
// TODO(jelbourn): make down-arrow a button to open the calendar
66
// TODO(jelbourn): aria attributes tying together date input and floating calendar.
7-
// TODO(jelbourn): actual calendar icon next to input
87
// TODO(jelbourn): something for mobile (probably calendar panel should take up entire screen)
9-
// TODO(jelbourn): style to match specification
108
// TODO(jelbourn): make sure this plays well with validation and ngMessages.
119
// TODO(jelbourn): forward more attributes to the internal input (required, autofocus, etc.)
1210
// TODO(jelbourn): floating panel open animation (see animation for menu in spec).
1311
// TODO(jelbourn): error state
12+
// TODO(jelbourn): auto-grow input to accomodate longer dates
1413

1514
// FUTURE VERSION
1615
// TODO(jelbourn): input behavior (masking? auto-complete?)
@@ -30,7 +29,11 @@
3029
'</md-button>' +
3130
'<div class="md-datepicker-input-container">' +
3231
'<input class="md-datepicker-input">' +
33-
'<div class="md-datepicker-expand-triangle" ng-hide="ctrl.isCalendarOpen"></div>' +
32+
33+
'<md-button md-no-ink class="md-datepicker-triangle-button md-icon-button" ' +
34+
'ng-click="ctrl.openCalendarPane()">' +
35+
'<div class="md-datepicker-expand-triangle"></div>' +
36+
'</md-button>' +
3437
'</div>' +
3538

3639
// This pane (and its shadow) will be detached from here and re-attached to the
@@ -43,9 +46,12 @@
4346
// inline input / trigger as one shadowed whole.
4447
'<div class="md-date-calendar-pane-shadow md-whiteframe-z1"></div>',
4548
require: ['ngModel', 'mdDatePicker'],
46-
scope: {},
49+
scope: {
50+
placeholder: '@mdPlaceholder'
51+
},
4752
controller: DatePickerCtrl,
4853
controllerAs: 'ctrl',
54+
bindToController: true,
4955
link: function(scope, element, attr, controllers) {
5056
var ngModelCtrl = controllers[0];
5157
var mdDatePickerCtrl = controllers[1];
@@ -98,6 +104,9 @@
98104
/** @type {HTMLElement} Shadow for floating calendar pane and input trigger. */
99105
this.calendarShadow = $element[0].querySelector('.md-date-calendar-pane-shadow');
100106

107+
/** @type {HTMLElement} Calendar icon button. */
108+
this.calendarButton = $element[0].querySelector('.md-date-picker-button');
109+
101110
/** @final {!angular.JQLite} */
102111
this.$element = $element;
103112

@@ -109,15 +118,15 @@
109118

110119
/** @type {boolean} */
111120
this.isDisabled;
112-
this.setDisabled($element[0].disabled);
121+
this.setDisabled($element[0].disabled || angular.isString($attrs['disabled']));
113122

114123
/** @type {boolean} Whether the date-picker's calendar pane is open. */
115124
this.isCalendarOpen = false;
116125

117126
/** Pre-bound click handler is saved so that the event listener can be removed. */
118127
this.bodyClickHandler = this.handleBodyClick.bind(this);
119128

120-
// Unless the user specifies so, the calendar should not be a tab stop.
129+
// Unless the user specifies so, the datepicker should not be a tab stop.
121130
// This is necessary because ngAria might add a tabindex to anything with an ng-model
122131
// (based on whether or not the user has turned that particular feature on/off).
123132
if (!$attrs['tabindex']) {
@@ -196,7 +205,10 @@
196205
});
197206
};
198207

199-
/** Capture properties set to the date-picker and imperitively handle internal changes. */
208+
/**
209+
* Capture properties set to the date-picker and imperitively handle internal changes.
210+
* This is done to avoid setting up additional $watches.
211+
*/
200212
DatePickerCtrl.prototype.installPropertyInterceptors = function() {
201213
var self = this;
202214

@@ -206,6 +218,11 @@
206218
get: function() { return self.isDisabled; },
207219
set: function(value) { self.setDisabled(value) }
208220
});
221+
222+
Object.defineProperty(this, 'placeholder', {
223+
get: function() { return self.inputElement.placeholder },
224+
set: function(value) { self.inputElement.placeholder = value; }
225+
});
209226
};
210227

211228
/**
@@ -220,6 +237,8 @@
220237
/** Position and attach the floating calendar to the document. */
221238
DatePickerCtrl.prototype.attachCalendarPane = function() {
222239
this.inputContainer.classList.add('md-open');
240+
this.calendarButton.classList.add('md-open');
241+
223242
var elementRect = this.inputContainer.getBoundingClientRect();
224243

225244
this.calendarPane.style.left = (elementRect.left + window.pageXOffset) + 'px';
@@ -240,6 +259,8 @@
240259
/** Detach the floating calendar pane from the document. */
241260
DatePickerCtrl.prototype.detachCalendarPane = function() {
242261
this.inputContainer.classList.remove('md-open');
262+
this.calendarButton.classList.remove('md-open');
263+
243264
// Use native DOM removal because we do not want any of the angular state of this element
244265
// to be disposed.
245266
this.calendarPane.parentNode.removeChild(this.calendarPane);
@@ -248,7 +269,7 @@
248269

249270
/** Open the floating calendar pane. */
250271
DatePickerCtrl.prototype.openCalendarPane = function() {
251-
if (!this.isCalendarOpen) {
272+
if (!this.isCalendarOpen && !this.isDisabled) {
252273
this.isCalendarOpen = true;
253274
this.attachCalendarPane();
254275
this.focusCalendar();

src/components/calendar/datePicker.scss

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ $md-datepicker-button-gap: 12px;
2424
display: inline-block;
2525
box-sizing: border-box;
2626
background: none;
27+
28+
&.md-open {
29+
fill: lightblue;
30+
}
2731
}
2832

2933
// The input into which the user can type the date.
@@ -51,7 +55,12 @@ $md-datepicker-button-gap: 12px;
5155

5256
.md-datepicker-input {
5357
margin-left: 24px;
54-
line-height: 40px;
58+
//line-height: 40px;
59+
height: 40px;
60+
}
61+
62+
.md-datepicker-expand-triangle {
63+
display: none;
5564
}
5665
}
5766
}
@@ -77,11 +86,30 @@ $md-datepicker-button-gap: 12px;
7786
}
7887

7988

89+
.md-datepicker-triangle-button {
90+
position: absolute;
91+
right: 0;
92+
top: 0;
93+
transform: translateY(-25%) translateX(45%);
94+
95+
&:hover .md-datepicker-expand-triangle {
96+
border-top-color: rgba(black, 0.54);
97+
}
98+
}
99+
100+
// Need crazy specificity to override .md-button.md-icon-button
101+
.md-datepicker-triangle-button.md-button.md-icon-button {
102+
height: auto;
103+
}
104+
80105
$md-date-arrow-size: 6px;
81106
.md-datepicker-expand-triangle {
107+
// Center the triangle inside of the button so that the
108+
// ink ripple origin looks correct.
82109
position: absolute;
83-
right: 0;
84110
top: 50%;
111+
left: 50%;
112+
transform: translate(-50%, -50%);
85113

86114
width: 0;
87115
height: 0;

src/components/calendar/demoDatePicker/index.html

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,17 @@ <h2>Development tools</h2>
1111
</p>
1212
<hr>
1313

14-
<md-date-picker ng-model="myDate"></md-date-picker>
14+
<md-date-picker ng-model="myDate" md-placeholder="Enter date"></md-date-picker>
15+
16+
<hr>
17+
<h3>Disabled with ng-disabled</h3>
18+
<md-date-picker ng-model="myDate" md-placeholder="Enter date" ng-disabled="true">
19+
</md-date-picker>
20+
21+
<hr>
22+
23+
<h3>Disabled with static disabled attribute</h3>
24+
<md-date-picker ng-model="myDate" placeholder="Enter date" disabled></md-date-picker>
1525

1626
<br><br>
1727
<br><br>

0 commit comments

Comments
 (0)