164 lines
4.4 KiB
SCSS
164 lines
4.4 KiB
SCSS
|
/// Shorthand Syntax Parser
|
|||
|
/// =======================
|
|||
|
/// The syntax parser converts [shorthand syntax][short]
|
|||
|
/// into a map of settings that can be compared/merged with
|
|||
|
/// other config maps and global setting.
|
|||
|
///
|
|||
|
/// [short]: b-api.html
|
|||
|
///
|
|||
|
/// @group x-parser
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Parse
|
|||
|
// -----
|
|||
|
/// The `parse` function provides all the syntax-sugar in Susy,
|
|||
|
/// converting user shorthand
|
|||
|
/// into a usable map of keys and values
|
|||
|
/// that can be normalized and passed to Su.
|
|||
|
///
|
|||
|
/// @group x-parser
|
|||
|
/// @see $susy
|
|||
|
///
|
|||
|
/// @param {list} $shorthand -
|
|||
|
/// Shorthand expression to define the width of the span,
|
|||
|
/// optionally containing:
|
|||
|
/// - a count, length, or column-list span;
|
|||
|
/// - `at $n`, `first`, or `last` location on asymmetrical grids;
|
|||
|
/// - `narrow`, `wide`, or `wider` for optionally spreading
|
|||
|
/// across adjacent gutters;
|
|||
|
/// - `of $n <spread>` for available grid columns
|
|||
|
/// and spread of the container
|
|||
|
/// (span counts like `of 6` are only valid
|
|||
|
/// in the context of symmetrical grids);
|
|||
|
/// - and `set-gutters $n` to override global gutter settings
|
|||
|
/// @param {bool} $context-only [false] -
|
|||
|
/// Allow the parser to ignore span and span-spread values,
|
|||
|
/// only parsing context and container-spread.
|
|||
|
/// This makes it possible to accept spanless values,
|
|||
|
/// like the `gutters()` syntax.
|
|||
|
/// When parsing context-only,
|
|||
|
/// the `of` indicator is optional.
|
|||
|
///
|
|||
|
/// @return {map} -
|
|||
|
/// Map of span and grid settings
|
|||
|
/// parsed from shorthand input –
|
|||
|
/// including all the properties available globally –
|
|||
|
/// `columns`, `gutters`, `spread`, `container-spread` –
|
|||
|
/// along with the span-specific properties
|
|||
|
/// `span`, and `location`.
|
|||
|
///
|
|||
|
/// @throw
|
|||
|
/// when a shorthand value is not recognized
|
|||
|
@function susy-parse(
|
|||
|
$shorthand,
|
|||
|
$context-only: false
|
|||
|
) {
|
|||
|
$parse-error: 'Unknown shorthand property:';
|
|||
|
$options: (
|
|||
|
'first': 'location',
|
|||
|
'last': 'location',
|
|||
|
'alpha': 'location',
|
|||
|
'omega': 'location',
|
|||
|
'narrow': 'spread',
|
|||
|
'wide': 'spread',
|
|||
|
'wider': 'spread',
|
|||
|
);
|
|||
|
|
|||
|
$return: ();
|
|||
|
$span: null;
|
|||
|
$columns: null;
|
|||
|
|
|||
|
$of: null;
|
|||
|
$next: false;
|
|||
|
|
|||
|
// Allow context-only shorthand, without span
|
|||
|
@if ($context-only) and (not index($shorthand, 'of')) {
|
|||
|
@if su-valid-columns($shorthand, 'fail-silent') {
|
|||
|
$shorthand: 'of' $shorthand;
|
|||
|
} @else {
|
|||
|
$shorthand: join('of', $shorthand);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// loop through the shorthand list
|
|||
|
@for $i from 1 through length($shorthand) {
|
|||
|
$item: nth($shorthand, $i);
|
|||
|
$type: type-of($item);
|
|||
|
$error: false;
|
|||
|
$details: '[#{$type}] `#{$item}`';
|
|||
|
|
|||
|
// if we know what's supposed to be coming next…
|
|||
|
@if $next {
|
|||
|
|
|||
|
// Add to the return map
|
|||
|
$return: map-merge($return, ($next: $item));
|
|||
|
|
|||
|
// Reset next to `false`
|
|||
|
$next: false;
|
|||
|
|
|||
|
} @else { // If we don't know what's supposed to be coming…
|
|||
|
|
|||
|
// Keywords…
|
|||
|
@if ($type == 'string') {
|
|||
|
// Check the map for keywords…
|
|||
|
@if map-has-key($options, $item) {
|
|||
|
$setting: map-get($options, $item);
|
|||
|
|
|||
|
// Spread could be on the span or the container…
|
|||
|
@if ($setting == 'spread') and ($of) {
|
|||
|
$return: map-merge($return, ('container-spread': $item));
|
|||
|
} @else {
|
|||
|
$return: map-merge($return, ($setting: $item));
|
|||
|
}
|
|||
|
|
|||
|
} @else if ($item == 'all') {
|
|||
|
// `All` is a span shortcut
|
|||
|
$span: 'all';
|
|||
|
} @else if ($item == 'at') {
|
|||
|
// Some keywords setup what's next…
|
|||
|
$next: 'location';
|
|||
|
} @else if ($item == 'set-gutters') {
|
|||
|
$next: 'gutters';
|
|||
|
} @else if ($item == 'of') {
|
|||
|
$of: true;
|
|||
|
} @else {
|
|||
|
$error: true;
|
|||
|
}
|
|||
|
|
|||
|
} @else if ($type == 'number') or ($type == 'list') { // Numbers & lists…
|
|||
|
|
|||
|
@if not ($span or $of) {
|
|||
|
// We don't have a span, and we're not expecting context…
|
|||
|
$span: $item;
|
|||
|
} @else if ($of) and (not $columns) {
|
|||
|
// We are expecting context…
|
|||
|
$columns: $item;
|
|||
|
} @else {
|
|||
|
$error: true;
|
|||
|
}
|
|||
|
|
|||
|
} @else {
|
|||
|
$error: true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@if $error {
|
|||
|
@return _susy-error('#{$parse-error} #{$details}', 'susy-parse');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If we have span, merge it in
|
|||
|
@if $span {
|
|||
|
$return: map-merge($return, ('span': $span));
|
|||
|
}
|
|||
|
|
|||
|
// If we have columns, merge them in
|
|||
|
@if $columns {
|
|||
|
$return: map-merge($return, ('columns': $columns));
|
|||
|
}
|
|||
|
|
|||
|
// Return the map of settings…
|
|||
|
@return $return;
|
|||
|
}
|